cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 bootloader form SD card

piotr2399
Associate II
Posted on August 21, 2015 at 09:04

Hello !

I have a problem with my bootloader form SD card. I think i try everything, now i don't have any ideas. App in sd card have changed memory start address to 0x08002000 and memory size to 0x0003E000. Can someone look for it and help ? Microcontroller is : STM32F107VC. Thanks !

#include <board_led.h>
#include <util_delay.h>
#include ''stm32f10x.h''
#include ''stm32f10x_gpio.h''
#include ''stm32f10x_rcc.h''
#include ''stm32f10x_flash.h''
#include ''ff.h''
#include ''diskio.h''
#include ''init_spi.h''
#include <stdio.h>
#define DEF_APP_ADDRESS 0x8002000
#define FLASH_KEY1 ((u32)0x45670123)
#define FLASH_KEY2 ((u32)0xCDEF89AB)
#define CR_LOCK_Set ((u32)0x00000080)
#define EraseTimeout ((u32)0x00000FFF)
#define CR_PER_Set ((u32)0x00000002)
#define CR_PER_Reset ((u32)0x00001FFD)
#define CR_STRT_Set ((u32)0x00000040)
#define ProgramTimeout ((u32)0x0000000F)
#define CR_PG_Set ((u32)0x00000001)
#define CR_PG_Reset ((u32)0x00001FFE)
void
FlashUnlock(
void
);
void
FlashLock(
void
);
uint32_t FlashErasePage(uint32_t page_address);
uint32_t FlashWritePage(uint32_t page_address, 
const
uint8_t *chunk, uint32_t chunk_len);
void
switch_to_main_app(
void
);
uint8_t is_app_correct(
void
);
FATFS FatFs; 
/* Work area (file system object) for logical drive */
uint16_t page_piece = 0;
uint32_t address_shift = 0;
int
main(
void
) {
static
const
unsigned delay_time = 80000;
LEDconfigure();
init_spi();
RedLEDon();
GreenLEDoff();
FIL file;
FRESULT fresult;
UINT len;
static
BYTE buffer[256];
fresult = f_mount(&FatFs, 
''''
, 0);
if
(fresult == FR_OK)
fresult = f_open(&file,
''update.bin''
, FA_OPEN_EXISTING | FA_READ); 
// Sprawdzenie czy jest plik z programem
// Warunku uruchomienia bootloadera
if
((fresult == FR_OK) || !is_app_correct()) {
FlashUnlock();
do
{
if
(!page_piece){
if
(FlashErasePage(DEF_APP_ADDRESS + address_shift))
break
;
}
fresult = f_read(&file,buffer,256,&len);
if
(fresult == FR_OK)
GreenLEDon();
else
GreenLEDoff();
if
(fresult != FR_OK)
break
;
if
(FlashWritePage(DEF_APP_ADDRESS + address_shift,(uint8_t *)buffer,(uint32_t)len))
break
;
address_shift += len;
page_piece++;
if
((page_piece << 8) == 1024) { 
page_piece = 0;
}
}
while
(len == 256);
FlashLock();
fresult = f_close(&file);
}
switch_to_main_app();
while
(1) {
RedLEDon();
Delay(delay_time);
RedLEDoff();
Delay(delay_time);
}
}
void
switch_to_main_app(
void
) {
typedef 
void
(*function_ptr)(
void
);
function_ptr firmware;
uint32_t addr = 0x08002000;
//__set_PRIMASK(1); //wylaczenie przerwan
//SysTick->CTRL = 0;
//SysTick->LOAD = 0;
//SysTick->VAL = 0;
__set_MSP(*(uint32_t*)addr);
__set_PSP(*(uint32_t*)addr); 
//ta linia nie jest konieczna
__set_CONTROL(0);
SCB->VTOR = (volatile uint32_t)(0x08002000); 
// set vector table
const
uint32_t firmware_entry = *(volatile uint32_t*)(0x08002000 + 4);
firmware = (function_ptr)(firmware_entry);
(*firmware)(); 
// jump to firmware
}
uint8_t is_app_correct(
void
) {
uint32_t *app_vector_isr;
app_vector_isr = (uint32_t *)DEF_APP_ADDRESS;
// app seems to be incorrect
if
((app_vector_isr[0] == 0xffffffff) || (app_vector_isr[0] == 0x0) ||
(app_vector_isr[1] == 0xffffffff) || (app_vector_isr[1] == 0x0))
{
return
(0);
}
return
(1);
}
void
FlashUnlock(
void
) {
/* Authorize the FPEC Access */
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
void
FlashLock(
void
) {
/* Set the Lock Bit to lock the FPEC and the FCR */
FLASH->CR |= CR_LOCK_Set;
}
uint32_t FlashErasePage(uint32_t page_address) {
FLASH_Status status;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if
(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase the page */
FLASH->CR|= CR_PER_Set;
FLASH->AR = page_address;
FLASH->CR|= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if
(status != FLASH_BUSY)
{
/* if the erase operation is completed, disable the PER Bit */
FLASH->CR &= CR_PER_Reset;
}
}
/* Return the Erase Status */
return
(status != FLASH_COMPLETE);
}
uint32_t FlashWritePage(uint32_t page_address, 
const
uint8_t *chunk, uint32_t chunk_len) {
FLASH_Status status;
volatile uint16_t *wr_addr;
uint16_t *data;
uint32_t data_len;
wr_addr = (volatile uint16_t*)page_address;
data = (uint16_t*)chunk;
data_len = chunk_len / 2U;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(ProgramTimeout);
if
(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to program the new data */
FLASH->CR |= CR_PG_Set;
}
while
(data_len)
{
*wr_addr = *data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(ProgramTimeout);
if
(status == FLASH_COMPLETE)
{
if
(*wr_addr != *data)
{
status = FLASH_ERROR_WRP;
break
;
}
data++;
wr_addr++;
data_len--;
}
else
{
break
;
}
}
if
(status != FLASH_BUSY)
{
/* if the program operation is completed, disable the PG Bit */
FLASH->CR &= CR_PG_Reset;
}
return
(status != FLASH_COMPLETE);
}

#fatfs #stm32 #bootloader #sd
8 REPLIES 8
knielsen
Associate II
Posted on August 21, 2015 at 10:07

You did not write how it is not working. You should figure out (with GDB, LED-debugging, or something) where it goes wrong. Is the flash written correctly? Does it reach the entry point in the application?

I think your switch_to_main_app() function looks dubious. You have a lot of code after switching stacks with __set_MSP(), the compiler might generate code that accesses the wrong stack. Try putting that just before the jump to application, or better, put the switching and the jumping together in inline assembly.

Also, you do not seem to de-initialise the used peripherals. If any interrupts are enabled, they might cause a failure once the vector base register has been changed.

piotr2399
Associate II
Posted on August 21, 2015 at 12:56

Thanks for reply ! Now, small firmware in sd card (about 2kb) is working, but when i switch off supply, firmware goes to bootloader, not to main firmware. Also it's problem with bigger firmware. About 30kB doesn't work. I put GreenLEDon(); after do-while and it doesn't light. I've make a function start_bootloader and change this line:

if
(FlashWritePage(DEF_APP_ADDRESS + address_shift, buffer, len))

Also i've changed switch_to_main_app();

void
switch_to_main_app(
void
) {
typedef 
void
(*function_ptr)(
void
);
function_ptr firmware;
uint32_t addr = 0x08002000;
SCB->VTOR = (volatile uint32_t)(0x08002000); 
// set vector table
const
uint32_t firmware_entry = *(volatile uint32_t*)(0x08002000 + 4);
firmware = (function_ptr)(firmware_entry);
__set_MSP(*(uint32_t*)addr);
__set_PSP(*(uint32_t*)addr); 
//ta linia nie jest konieczna
__set_CONTROL(0);
(*firmware)(); 
// jump to firmware
}

knielsen
Associate II
Posted on August 21, 2015 at 14:01

Isn't the page size wrong in your code for flashing?

It seems to assume 1024-byte flash pages. But the STM32F107VC is listed as a ''connectivity'' device which has 2048-byte pages (according to the ST ''Flash programming manual'', PM0075).

This would make your code erase the first half of a page when writing the second half, so you would end up with only half your firmware flashed. Check, by dumping the flash out to your computer, that the complete firmware is correctly written.

It is normal that the bootloader is always called at boot, usually I think you would in your bootloader jump directly to the firmware if the SD card is not present.

piotr2399
Associate II
Posted on August 21, 2015 at 14:33

Do You mean this line ?

if((page_piece << 😎 == 1024)

page_piece = 0;

I've already change it to ''==2048'' I forgot to write about it, sorry,

but that

nothing has changed

Posted on August 21, 2015 at 15:59

Do you have a debugger? Can you refine what ''not working'' means with that?

Have you verified with a checksum/crc, or reading back with ST-LINK Utilities, that what's been written is correct?

Does your board have a serial port? Can you use that to better identify and diagnose what exactly is going on?

Does the image you have debug properly outside of the boot loader? Is it correctly configured for the address it's being loaded, and do you have any interrupts running that could cause issues?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
piotr2399
Associate II
Posted on August 21, 2015 at 20:35

I have a debugger but it doesn't work properly with bootloader. Debugger crashes in line of f_mount, but program goes on, so i can't use it.

Not working means that the bootloader not out from the do-while loop. I've put after loop GreenLEDOn(); and it doesn't light. When i put simple firmware to SD card (about 2kB) bootloader works properly.

On monday i will read flash by ST-LINK utility and compare with orginal .bin file. Some extra wires, soldering and UART will be available.

I think the firmware on SD card is properly set. Memory start address is 0x08002000 and memory size is 0x0003E000

Posted on August 21, 2015 at 21:16

What debug/toolset are you using?

Could you use the SWV debug output instead of using a UART? What about using the LED in different modes? Blinking fast/slow, duty cycle?

Instead of reading off the card, perhaps you can turn that around, and write a memory image to the card? You could also write to a log file.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
piotr2399
Associate II
Posted on August 24, 2015 at 10:09

Hi !

I found an error. My bootloader app occupies 15kB of flash, not 8kB. When i switched settings in app on sd card it works good. But i have one more problem. Small applications without interrupts etc are working. Bigger app (52kB) doesn't work.

I

read

data from the

flash memory

by ST

Link

utility

and

the program is

uploaded

correctly. I thnik problem the problem is switch_to_main_app. Is it correct like that ?

void
switch_to_main_app(
void
) {
typedef 
void
(*function_ptr)(
void
);
function_ptr firmware;
uint32_t addr = 0x08004000;
SCB->VTOR = (volatile uint32_t)(0x08004000); 
// set vector table (dla bootloadera o wielkosci 16kB)
const
uint32_t firmware_entry = *(volatile uint32_t*)(0x08004000 + 4);
firmware = (function_ptr)(firmware_entry);
__set_MSP(*(uint32_t*)addr);
__set_PSP(*(uint32_t*)addr); 
//ta linia nie jest konieczna
__set_CONTROL(0);
(*firmware)(); 
// jump to firmware
}