mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-02-05 07:48:14 +00:00
559 lines
10 KiB
C++
559 lines
10 KiB
C++
|
|
|
|
#define _FLASH_PROG 1
|
|
|
|
|
|
// Temp
|
|
#define SIGNATURE_0 0x1E
|
|
#define SIGNATURE_1 0x55 //0x97
|
|
#define SIGNATURE_2 0xAA //0x02
|
|
|
|
#define SIGNATURE_3 0x97
|
|
#define SIGNATURE_4 0x02
|
|
|
|
|
|
#define STM32F10X_CL
|
|
|
|
#include "stm32f10x.h"
|
|
|
|
#include "stk500.h"
|
|
#include "stm32f10x_flash.h"
|
|
|
|
#define OPTIBOOT_MAJVER 4
|
|
#define OPTIBOOT_MINVER 5
|
|
|
|
uint32_t ResetReason ;
|
|
uint32_t LongCount ;
|
|
uint8_t Buff[512] ;
|
|
|
|
uint8_t NotSynced ;
|
|
uint8_t Port ;
|
|
|
|
static void start_timer2()
|
|
{
|
|
TIM2->CNT = 0 ;
|
|
TIM2->PSC = 71 ; // 72-1;for 72 MHZ /1.0usec/(71+1)
|
|
TIM2->ARR = 0xFFFF; //count till max
|
|
}
|
|
|
|
void RCC_DeInit(void)
|
|
{
|
|
/* Disable APB2 Peripheral Reset */
|
|
RCC->APB2RSTR = 0x00000000;
|
|
|
|
/* Disable APB1 Peripheral Reset */
|
|
RCC->APB1RSTR = 0x00000000;
|
|
|
|
/* FLITF and SRAM Clock ON */
|
|
RCC->AHBENR = 0x00000014;
|
|
|
|
/* Disable APB2 Peripheral Clock */
|
|
RCC->APB2ENR = 0x00000000;
|
|
|
|
/* Disable APB1 Peripheral Clock */
|
|
RCC->APB1ENR = 0x00000000;
|
|
|
|
/* Set HSION bit */
|
|
RCC->CR |= (u32)0x00000001;
|
|
|
|
/* Reset SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], ADCPRE[1:0] and MCO[2:0] bits*/
|
|
RCC->CFGR &= 0xF8FF0000;
|
|
|
|
/* Reset HSEON, CSSON and PLLON bits */
|
|
RCC->CR &= 0xFEF6FFFF;
|
|
|
|
/* Reset HSEBYP bit */
|
|
RCC->CR &= 0xFFFBFFFF;
|
|
|
|
/* Reset PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE bits */
|
|
RCC->CFGR &= 0xFF80FFFF;
|
|
|
|
/* Disable all interrupts */
|
|
RCC->CIR = 0x009F0000;
|
|
}
|
|
|
|
void disableInterrupts()
|
|
{
|
|
__disable_irq() ;
|
|
NVIC_DisableIRQ(USART1_IRQn) ;
|
|
NVIC_DisableIRQ(USART2_IRQn) ;
|
|
NVIC_DisableIRQ(USART3_IRQn) ;
|
|
NVIC_DisableIRQ(TIM1_BRK_IRQn) ;
|
|
NVIC_DisableIRQ(TIM1_UP_IRQn) ;
|
|
NVIC_DisableIRQ(TIM1_TRG_COM_IRQn) ;
|
|
NVIC_DisableIRQ(TIM1_CC_IRQn) ;
|
|
NVIC_DisableIRQ(TIM3_IRQn) ;
|
|
NVIC_DisableIRQ(TIM4_IRQn) ;
|
|
NVIC_DisableIRQ(ADC1_2_IRQn) ;
|
|
SysTick->CTRL = 0 ;
|
|
}
|
|
|
|
|
|
static void executeApp()
|
|
{
|
|
// Expected at 0x08002000
|
|
uint32_t *p ;
|
|
|
|
// Disable all peripheral clocks
|
|
// Disable used PLL
|
|
// Disable interrupts
|
|
// Clear pending interrupts
|
|
|
|
p = (uint32_t *) 0x08002000 ;
|
|
|
|
if ( *p == 0x20005000 )
|
|
{
|
|
|
|
USART1->CR1 = 0 ;
|
|
USART1->BRR = 0 ;
|
|
USART2->CR1 = 0 ;
|
|
USART2->BRR = 0 ;
|
|
USART3->CR1 = 0 ;
|
|
USART3->BRR = 0 ;
|
|
(void) USART2->SR ;
|
|
(void) USART2->DR ;
|
|
(void) USART1->SR ;
|
|
(void) USART1->DR ;
|
|
USART1->SR = 0 ;
|
|
USART2->SR = 0 ;
|
|
USART3->SR = 0 ;
|
|
|
|
RCC->APB1ENR &= ~RCC_APB1ENR_USART2EN ; // Disable clock
|
|
RCC->APB1ENR &= ~RCC_APB1ENR_USART3EN ; // Disable clock
|
|
|
|
TIM2->CR1 = 0 ;
|
|
|
|
disableInterrupts() ;
|
|
|
|
NVIC->ICER[0] = 0xFFFFFFFF ;
|
|
NVIC->ICER[1] = 0xFFFFFFFF ;
|
|
NVIC->ICER[2] = 0xFFFFFFFF ;
|
|
NVIC->ICPR[0] = 0xFFFFFFFF ;
|
|
NVIC->ICPR[1] = 0xFFFFFFFF ;
|
|
NVIC->ICPR[2] = 0xFFFFFFFF ;
|
|
|
|
RCC_DeInit() ;
|
|
SysTick->CTRL = 0 ;
|
|
SysTick->LOAD = 0 ;
|
|
SysTick->VAL = 0 ;
|
|
|
|
asm(" mov.w r1, #134217728"); // 0x8000000
|
|
asm(" add.w r1, #8192"); // 0x2000
|
|
|
|
asm(" movw r0, #60680"); // 0xED08
|
|
asm(" movt r0, #57344"); // 0xE000
|
|
asm(" str r1, [r0, #0]"); // Set the VTOR
|
|
|
|
asm("ldr r0, [r1, #0]"); // Stack pointer value
|
|
asm("msr msp, r0"); // Set it
|
|
asm("ldr r0, [r1, #4]"); // Reset address
|
|
asm("mov.w r1, #1");
|
|
asm("orr r0, r1"); // Set lsbit
|
|
asm("bx r0"); // Execute application
|
|
}
|
|
}
|
|
|
|
|
|
static uint16_t test0()
|
|
{
|
|
if ( USART2->SR & USART_SR_RXNE )
|
|
{
|
|
return USART2->DR ;
|
|
}
|
|
return 0xFFFF ;
|
|
}
|
|
|
|
static uint16_t test1()
|
|
{
|
|
if ( USART1->SR & USART_SR_RXNE )
|
|
{
|
|
return USART1->DR ;
|
|
}
|
|
return 0xFFFF ;
|
|
}
|
|
|
|
uint8_t getch1()
|
|
{
|
|
while ( ( USART1->SR & USART_SR_RXNE ) == 0 )
|
|
{
|
|
IWDG->KR = 0xAAAA ; // reload
|
|
if ( TIM2->SR & TIM_SR_UIF )
|
|
{
|
|
TIM2->SR &= ~TIM_SR_UIF ;
|
|
GPIOA->ODR ^= 0x0002 ;
|
|
}
|
|
// wait
|
|
}
|
|
return USART1->DR ;
|
|
}
|
|
|
|
uint8_t getch()
|
|
{
|
|
if ( Port )
|
|
{
|
|
return getch1() ;
|
|
}
|
|
while ( ( USART2->SR & USART_SR_RXNE ) == 0 )
|
|
{
|
|
IWDG->KR = 0xAAAA ; // reload
|
|
if ( TIM2->SR & TIM_SR_UIF )
|
|
{
|
|
TIM2->SR &= ~TIM_SR_UIF ;
|
|
GPIOA->ODR ^= 0x0002 ;
|
|
}
|
|
// wait
|
|
}
|
|
return USART2->DR ;
|
|
}
|
|
|
|
void putch( uint8_t byte )
|
|
{
|
|
if ( Port )
|
|
{
|
|
while ( ( USART1->SR & USART_SR_TXE ) == 0 )
|
|
{
|
|
// wait
|
|
}
|
|
USART1->DR = byte ;
|
|
}
|
|
else
|
|
{
|
|
while ( ( USART3->SR & USART_SR_TXE ) == 0 )
|
|
{
|
|
// wait
|
|
}
|
|
USART3->DR = byte ;
|
|
}
|
|
}
|
|
|
|
static void serialInit()
|
|
{
|
|
RCC->APB2ENR |= RCC_APB2ENR_USART1EN ; // Enable clock
|
|
RCC->APB1ENR |= RCC_APB1ENR_USART2EN ; // Enable clock
|
|
RCC->APB1ENR |= RCC_APB1ENR_USART3EN ; // Enable clock
|
|
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN ;
|
|
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN ;
|
|
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN ;
|
|
|
|
GPIOA->CRH = GPIOA->CRH & 0xFFFFFF0F | 0x00000090 ; // PA9
|
|
// USART2 TX is PA2, only Rx used
|
|
// USART3 TX is PB10, only Tx used
|
|
GPIOB->CRH = GPIOB->CRH & 0xFFFFF0FF | 0x00000900 ; // PB10
|
|
|
|
USART1->BRR = 72000000 / 57600 ;
|
|
USART1->CR1 = 0x200C ;
|
|
USART2->BRR = 36000000 / 57600 ;
|
|
USART2->CR1 = 0x200C ;
|
|
USART2->CR2 = 0 ;
|
|
USART2->CR3 = 0 ;
|
|
USART3->BRR = 36000000 / 57600 ;
|
|
USART3->CR1 = 0x200C ;
|
|
USART3->CR2 = 0 ;
|
|
USART3->CR3 = 0 ;
|
|
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
serialInit() ;
|
|
start_timer2() ;//0.5us
|
|
FLASH_Unlock() ;
|
|
GPIOA->BSRR = 0x000000F1 ;
|
|
GPIOA->CRL = GPIOA->CRL & 0x0000FF00 | 0x88880028 ; // LED and inputs
|
|
|
|
// Input with pullup, 1000B, and set the ODR bit
|
|
|
|
GPIOB->CRL = GPIOB->CRL & 0xFFFF0F0F | 0x00002020 ; // PB1 and PB3, invert controls
|
|
GPIOB->BRR = 0x00000008 ;
|
|
GPIOB->BSRR = 0x00000002 ;
|
|
|
|
}
|
|
|
|
void verifySpace()
|
|
{
|
|
if ( getch() != CRC_EOP)
|
|
{
|
|
NotSynced = 1 ;
|
|
return ;
|
|
|
|
}
|
|
putch(STK_INSYNC);
|
|
}
|
|
|
|
void bgetNch(uint8_t count)
|
|
{
|
|
do
|
|
{
|
|
getch() ;
|
|
} while (--count) ;
|
|
verifySpace() ;
|
|
}
|
|
|
|
void loader( uint32_t check )
|
|
{
|
|
uint8_t ch ;
|
|
uint8_t GPIOR0 ;
|
|
uint32_t address = 0 ;
|
|
uint8_t lastCh ;
|
|
|
|
ResetReason = RCC->CSR ;
|
|
RCC->CSR |= RCC_CSR_RMVF ;
|
|
if ( ResetReason & RCC_CSR_SFTRSTF )
|
|
{
|
|
check = 0 ; // Stay in bootloader
|
|
}
|
|
|
|
NVIC_DisableIRQ(TIM2_IRQn) ;
|
|
if ( check )
|
|
{
|
|
TIM2->CNT = 0 ;
|
|
TIM2->SR &= ~TIM_SR_UIF ;
|
|
while ( ( TIM2->SR & TIM_SR_UIF ) == 0 )
|
|
{
|
|
// wait
|
|
}
|
|
TIM2->SR &= ~TIM_SR_UIF ;
|
|
|
|
while ( ( TIM2->SR & TIM_SR_UIF ) == 0 )
|
|
{
|
|
// wait
|
|
}
|
|
TIM2->SR &= ~TIM_SR_UIF ;
|
|
|
|
ch = GPIOA->IDR & 0xF1 ;
|
|
if ( ch != 0xF0 )
|
|
{
|
|
return ;
|
|
}
|
|
}
|
|
disableInterrupts() ;
|
|
|
|
NotSynced = 1 ;
|
|
lastCh = 0 ;
|
|
for (;;)
|
|
{
|
|
while ( NotSynced )
|
|
{
|
|
uint16_t data ;
|
|
|
|
data = test0() ;
|
|
if ( data != 0xFFFF )
|
|
{
|
|
ch = data ;
|
|
if ( ( lastCh == STK_GET_SYNC ) && ( ch == CRC_EOP ) )
|
|
{
|
|
NotSynced = 0 ;
|
|
Port = 0 ;
|
|
break ;
|
|
}
|
|
lastCh = ch ;
|
|
}
|
|
data = test1() ;
|
|
if ( data != 0xFFFF )
|
|
{
|
|
ch = data ;
|
|
if ( ( lastCh == STK_GET_SYNC ) && ( ch == CRC_EOP ) )
|
|
{
|
|
NotSynced = 0 ;
|
|
Port = 1 ;
|
|
break ;
|
|
}
|
|
lastCh = ch ;
|
|
}
|
|
IWDG->KR = 0xAAAA ; // reload
|
|
if ( TIM2->SR & TIM_SR_UIF )
|
|
{
|
|
TIM2->SR &= ~TIM_SR_UIF ;
|
|
GPIOA->ODR ^= 0x0002 ;
|
|
}
|
|
}
|
|
|
|
/* get character from UART */
|
|
ch = getch() ;
|
|
if(ch == STK_GET_PARAMETER)
|
|
{
|
|
GPIOR0 = getch() ;
|
|
verifySpace() ;
|
|
if (GPIOR0 == 0x82)
|
|
{
|
|
putch(OPTIBOOT_MINVER) ;
|
|
}
|
|
else if (GPIOR0 == 0x81)
|
|
{
|
|
putch(OPTIBOOT_MAJVER) ;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* GET PARAMETER returns a generic 0x03 reply for
|
|
* other parameters - enough to keep Avrdude happy
|
|
*/
|
|
putch(0x03) ;
|
|
}
|
|
}
|
|
else if(ch == STK_SET_DEVICE)
|
|
{
|
|
// SET DEVICE is ignored
|
|
bgetNch(20) ;
|
|
}
|
|
else if(ch == STK_SET_DEVICE_EXT)
|
|
{
|
|
// SET DEVICE EXT is ignored
|
|
bgetNch(5);
|
|
}
|
|
else if(ch == STK_LOAD_ADDRESS)
|
|
{
|
|
// LOAD ADDRESS
|
|
uint16_t newAddress ;
|
|
newAddress = getch() ;
|
|
newAddress = (newAddress & 0xff) | (getch() << 8);
|
|
address = newAddress ; // Convert from word address to byte address
|
|
address <<= 1 ;
|
|
verifySpace() ;
|
|
}
|
|
else if(ch == STK_UNIVERSAL)
|
|
{
|
|
// UNIVERSAL command is ignored
|
|
bgetNch(4) ;
|
|
putch(0x00) ;
|
|
}
|
|
else if(ch == STK_PROG_PAGE)
|
|
{
|
|
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
|
uint8_t *bufPtr;
|
|
uint16_t addrPtr;
|
|
uint16_t length ;
|
|
uint16_t count ;
|
|
uint16_t data ;
|
|
uint8_t *memAddress ;
|
|
length = getch() << 8 ; /* getlen() */
|
|
length |= getch() ;
|
|
getch() ; // discard flash/eeprom byte
|
|
// While that is going on, read in page contents
|
|
count = length ;
|
|
bufPtr = Buff;
|
|
do
|
|
{
|
|
*bufPtr++ = getch() ;
|
|
}
|
|
while (--count) ;
|
|
if ( length & 1 )
|
|
{
|
|
*bufPtr = 0xFF ;
|
|
}
|
|
count = length ;
|
|
count += 1 ;
|
|
count /= 2 ;
|
|
memAddress = (uint8_t *)(address + 0x08000000) ;
|
|
|
|
if ( (uint32_t)memAddress < 0x08020000 )
|
|
{
|
|
// Read command terminator, start reply
|
|
verifySpace();
|
|
|
|
if ( (uint32_t)memAddress >= 0x08002000 )
|
|
{
|
|
if ( ((uint32_t)memAddress & 0x000003FF) == 0 )
|
|
{
|
|
// At page start so erase it
|
|
FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);
|
|
FLASH_ErasePage( (uint32_t)memAddress ) ;
|
|
}
|
|
bufPtr = Buff;
|
|
while ( count )
|
|
{
|
|
data = *bufPtr++ ;
|
|
data |= *bufPtr++ << 8 ;
|
|
FLASH_ProgramHalfWord( (uint32_t)memAddress, data ) ;
|
|
memAddress += 2 ;
|
|
count -= 1 ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
verifySpace();
|
|
}
|
|
}
|
|
else if(ch == STK_READ_PAGE)
|
|
{
|
|
uint16_t length ;
|
|
uint8_t xlen ;
|
|
uint8_t *memAddress ;
|
|
memAddress = (uint8_t *)(address + 0x08000000) ;
|
|
// READ PAGE - we only read flash
|
|
xlen = getch() ; /* getlen() */
|
|
length = getch() | (xlen << 8 ) ;
|
|
getch() ;
|
|
verifySpace() ;
|
|
do
|
|
{
|
|
putch( *memAddress++) ;
|
|
}
|
|
while (--length) ;
|
|
|
|
|
|
}
|
|
else if(ch == STK_READ_SIGN)
|
|
{
|
|
// READ SIGN - return what Avrdude wants to hear
|
|
verifySpace() ;
|
|
putch(SIGNATURE_0) ;
|
|
if ( Port )
|
|
{
|
|
putch(SIGNATURE_3) ;
|
|
putch(SIGNATURE_4) ;
|
|
}
|
|
else
|
|
{
|
|
putch(SIGNATURE_1) ;
|
|
putch(SIGNATURE_2) ;
|
|
}
|
|
}
|
|
else if (ch == STK_LEAVE_PROGMODE)
|
|
{ /* 'Q' */
|
|
// Adaboot no-wait mod
|
|
|
|
// watchdogConfig(WATCHDOG_16MS);
|
|
|
|
verifySpace() ;
|
|
}
|
|
else
|
|
{
|
|
// This covers the response to commands like STK_ENTER_PROGMODE
|
|
verifySpace() ;
|
|
}
|
|
if ( NotSynced )
|
|
{
|
|
continue ;
|
|
}
|
|
putch(STK_OK);
|
|
}
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
loader(1) ;
|
|
|
|
// Execute loaded application
|
|
executeApp() ;
|
|
|
|
loader(0) ;
|
|
|
|
// The next bit not really needed as loader(0) doesn't return
|
|
for(;;)
|
|
{
|
|
if ( TIM2->SR & TIM_SR_UIF )
|
|
{
|
|
TIM2->SR &= ~TIM_SR_UIF ;
|
|
if ( ++LongCount > 4 )
|
|
{
|
|
GPIOA->ODR ^= 0x0002 ;
|
|
LongCount = 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|