210 lines
6.8 KiB
C
210 lines
6.8 KiB
C
|
|
#include "usb.h"
|
|
#include "io.h"
|
|
#include "buffer.h"
|
|
#include "bootload.h"
|
|
#include "jtag.h"
|
|
|
|
#ifdef AVR_CORE
|
|
#include <avr/interrupt.h>
|
|
#include <avr/wdt.h>
|
|
#include <util/delay.h>
|
|
#include "usbdrv.h"
|
|
#endif
|
|
|
|
#ifdef STM_CORE
|
|
#include <stm32f0xx.h>
|
|
#include "../source_stm_only/stm_init.h"
|
|
#endif
|
|
|
|
|
|
|
|
int main(void)
|
|
{
|
|
|
|
#ifdef AVR_CORE
|
|
//set watch dog timer with 1 second timer
|
|
wdt_enable(WDTO_1S);
|
|
/* Even if you don't use the watchdog, turn it off here. On newer devices,
|
|
* the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
|
|
*/
|
|
/* RESET status: all port bits are inputs without pull-up.
|
|
* That's the way we need D+ and D-. Therefore we don't need any
|
|
* additional hardware initialization.
|
|
*/
|
|
|
|
//initialize V-usb driver before interupts enabled and entering main loop
|
|
usbInit();
|
|
//disconnect from host enforce re-enumeration, interupts must be disabled during this.
|
|
usbDeviceDisconnect();
|
|
|
|
//fake USB disconnect for over 250ms
|
|
uint8_t index = 0;
|
|
while(--index){ //loop 256 times
|
|
wdt_reset(); //keep wdt happy during this time
|
|
_delay_ms(1); //delay 256msec
|
|
}
|
|
|
|
//reconnect to host
|
|
usbDeviceConnect();
|
|
|
|
|
|
//enable interrupts
|
|
sei();
|
|
#endif
|
|
|
|
#ifdef STM_CORE
|
|
|
|
//INDEPENDENT WATCH DOG TIMER
|
|
//has it's own clock circuit so even if the main clock fails the WDT
|
|
//will keep running, it's not as accurate as the System Window WDT
|
|
//but we don't care about accuracy for our needs.
|
|
//
|
|
//I can't make sense of the window option, so let's not bother with it..
|
|
//
|
|
//Configuring the IWDG when the window option is disabled
|
|
// When the window option it is not used, the IWDG can be configured as follows:
|
|
// 1.Enable the IWDG by writing 0x0000 CCCC in the IWDG_KR register.
|
|
#define wdt_enable() IWDG->KR = 0x0000CCCC
|
|
wdt_enable();
|
|
// 2. Enable register access by writing 0x00005555 in the IWDG_KR register.
|
|
IWDG->KR = 0x00005555;
|
|
//After this point the IWDG timer can NEVER be shut off, except via reset..
|
|
// 3. Write the IWDG prescaler by programming IWDG_PR from 0 to 7.
|
|
// default is zero divider / 4
|
|
// 40Khz clock input to prescaler
|
|
// divided by 4 = 10Khz
|
|
IWDG->PR = 2; // divided by 16 = 2.5Khz
|
|
// 4. Write the reload register (IWDG_RLR).
|
|
//12bit value that gets loaded into WDcounter each time counter is refreshed
|
|
//10Khz clock -> 1sec, need a value of 10,000 = 0x2710 too big
|
|
//12bit counter has max value of 4095
|
|
//2.5Khz clock -> 1sec, need value of 2500 ~= 2560 = 0xA00
|
|
IWDG->RLR = 0x0A00;
|
|
// 5. Wait for the registers to be updated (IWDG_SR = 0x00000000).
|
|
while( IWDG->SR ) { /* forever */ }
|
|
// 6. Refresh the counter value with IWDG_RLR (IWDG_KR = 0x0000 AAAA)
|
|
#define wdt_reset() IWDG->KR = 0x0000AAAA
|
|
wdt_reset();
|
|
//call this function atleast once a second to keep the device from resetting
|
|
|
|
//remap system memory (including vector table)
|
|
// SYSCFG->CFGR1 = 0x00000002; //boot value (BOOT1:0 = 0b10
|
|
// SYSCFG->CFGR1 = 0x00000001; //map sysmem bootloader to 0x00000000
|
|
//SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE_ | 0x0001;
|
|
//jump to bootloader
|
|
// jump_to_bootloader();
|
|
// jump_to_addr(0x1FFFC519);
|
|
|
|
//System is running at reset defaults
|
|
|
|
//Default clock is in operation
|
|
//Change system clock as needed
|
|
init_clock();
|
|
|
|
|
|
//now enable GPIO and set
|
|
|
|
//trying to move to 48Mhz clock for all STM32 cores
|
|
//If >24Mhz SYSCLK, must add wait state to flash
|
|
//can also enable prefetch buffer
|
|
FLASH->ACR = FLASH_ACR_PRFTBE | 0x0001;
|
|
//switch to 48Mhz
|
|
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
|
|
|
|
//Initialize periphery clocks as needed
|
|
//tried to have this done but usb code but wasn't working..
|
|
//having the main handle this prob makes more sense anyway, but would like to know
|
|
//why this didn't work..
|
|
init_usb_clock();
|
|
|
|
|
|
//init_usb();
|
|
//don't call the USB code directly,
|
|
//instead set the usb flag to tell it to initialize then jump to the USB ISR
|
|
//we know where the USB ISR is because of the vector table
|
|
usbflag = INITUSB;
|
|
|
|
typedef void (*pFunction)(void);
|
|
pFunction JumpToApplication;
|
|
//interrupts should already be disabled
|
|
JumpToApplication = (void (*)(void)) (*((uint32_t *) ((0x000000BC)))); //USB ISR vector location
|
|
|
|
//Jump to the USB ISR
|
|
JumpToApplication();
|
|
|
|
//set the usb_buff ram function pointers to USB ISR can use them
|
|
usbfuncwrite = (uint32_t) &usbFunctionWrite; //should only assign lower 16bits
|
|
usbfuncsetup = (uint32_t) &usbFunctionSetup; //should only assign lower 16bits
|
|
|
|
//Initialize WDT, core features, etc
|
|
|
|
//enable interrupts
|
|
__enable_irq(); //clear's processor PRIMASK register bit to allow interrupts to be taken
|
|
//I think this gets done automatically when enabling individual IRQs
|
|
|
|
//Initialize io, periphery, etc
|
|
//setup LED as outputs and turn them on
|
|
//setup user switch as input
|
|
|
|
|
|
#endif
|
|
|
|
//intialize i/o and LED to pullup state
|
|
io_reset();
|
|
|
|
//this is just a quick hack to allow measuring HSE with a scope w/o loading the circuit with probes.
|
|
//#define DRIVE_MCO
|
|
#ifdef DRIVE_MCO
|
|
//drive HSE (8Mhz) divided by 8 = 1Mhz for crystal load capacitor calibration
|
|
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_MCOPRE) | RCC_CFGR_MCOPRE_DIV8; /* MCO prescaler = div 8 */
|
|
//RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_MCOPRE) | RCC_CFGR_MCOPRE_DIV16; /* MCO prescaler = div 16 */
|
|
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_MCO) | RCC_CFGR_MCO_HSE; /* MCO source HSE */
|
|
//enable GPIO pin PA8 MCO AF0
|
|
//RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
|
|
//CTL_ENABLE();
|
|
nes_init();
|
|
//GPIOA->MODER = MODER_AF << (2*8U); //set PA8 to AF
|
|
GPIOA->MODER = 0x28020000; //set PA14, PA13, (SWD) & PA8 (MCO) to AF
|
|
//AF0 is the default value of GPIOx_AFRH/L registers so MCO is already selected as AF in use
|
|
#endif
|
|
|
|
//initialize jtag engine to be off
|
|
pbje_status = PBJE_OFF;
|
|
|
|
//=================
|
|
//MAIN LOOP
|
|
//=================
|
|
while (1) {
|
|
|
|
//pet the watch doggie to keep him happy
|
|
wdt_reset();
|
|
|
|
#ifdef AVR_CORE
|
|
//must call at regular intervals no longer than 50msec
|
|
//keeps 8Byte EP buffer moving from what I understand
|
|
usbPoll();
|
|
#endif
|
|
|
|
//check buffer status' and instruct them to
|
|
//flash/dump as needed to keep data moving
|
|
//currently assuming this operation doesn't take longer
|
|
//than 50msec to meet usbPoll's req't
|
|
//considering using a timer counter interupt to call
|
|
//usbPoll more often but going to see how speed is
|
|
//impacted first..
|
|
//256Bytes * 20usec Tbp = 5.12msec programming time
|
|
//+ cpu operations that can't be hid behind flash wait time
|
|
//another thought would be to call usbPoll mid programming
|
|
//a few times to prevent incoming data from being delayed too long
|
|
update_buffers();
|
|
|
|
//if paul's basic jtag engine "PBJE" is running, main
|
|
//thread needs to call engine at periodic intervals to keep it
|
|
//running.
|
|
if (pbje_status != PBJE_OFF) {
|
|
jtag_run_pbje();
|
|
}
|
|
}
|
|
}
|