In Cortex M3 microcontroller, When will variables in .data section of Flash are copied to SRAM,Is - cortex-m3

In Cortex M3 micro controller, When will variables in .data section of Flash are copied to SRAM,Is it before fetching of reset and initial SP pointers or later? Am using Keil4 and LPC 1778.

Here's how it normally goes:
MCU's bootloader does minimum HW init, reads SP and PC from FLASH, and starts user code;
User code copies .data from FLASH to RAM and zeroes .bss;
main() is called.
For example:
Reset handler: http://repo.or.cz/cbaos.git/blob/HEAD:/arch/arm-cortex-m3/crt.c
.data and .bss init :http://repo.or.cz/cbaos.git/blob/HEAD:/kernel/init.c

In the reset handler, .S file we can check the code how the flow is there.
In the initialization, before assigning SP, data will be copied

Related

Can't receive from USB bulk endpoint despite Windows enumerates and libusb reads descriptor of STM32 custom device class

For a fast ADC sampling USB device, I am using the USB 2.0 High Speed capable STM32F733 with the embedded USB-HS PHY. In USBView, I can see that the device is enumerated, the libusb code opens the device and claims interface, but when I try to receive data with libusb_bulk_transfer, the operation times out (return code -12). Things I have tried: I have confirmed than when I request data with libusb_bulk_transfer, the device is interrupted. Note: I have DMA enabled in my class configuration C file and it is not clear to me how that is triggered. I have verified that the transfersize and packet count registers are being set correctly by the LL library function, and that when I request data from
Any tips on debugging such problems will be much appreciated - this board is my undergrad thesis due in under two months!
Desktop sequence:
libusb_get_device_list, libusb_get_device_descriptor, libusb_open, libusb_get_string_descriptor_ascii, libusb_free_device_list, libusb_bulk_transfer(devh, fat_EPIN_ADDR, inframe, fat_EPIN_SIZE, &gotBytes, 100). Where gotBytes is integer, and inframe is a large array.
Device firmware:
MX_USB_DEVICE_Init();
uint8_t txBuffer[10*fat_EPIN_SIZE];
while (1)
{
USBD_LL_Transmit(&hUsbDeviceHS, Custom_fat_EPIN_ADDR, txBuffer, Custom_fat_EPIN_SIZE);
HAL_Delay(1);
}
Custom_fat_EPIN_SIZE is 0x200 and the endpoint address is 0x81 (EP IN 1)
Installed driver for device is WinUSB (verified in Device Manger to be winusb.sys), and I am linking libusb-1.0 into my desktop program. You can find my source code at https://gitlab.com/tywonemi-school-stuff/silicon-radar-fun, the firmware is My SW/v1 and the desktop software is a Qt Creator project in My SW/Viewer, of note is usb.cpp. You can also compare with testing project/HIDTest, which is code that I tested with STM32F303 nucleo dev board where I was able to read an array through IN bulk endpoint with the Viewer application. However, F3 has the USB peripheral, while F7 has OTG_USB, and I am now attempting USB 2.0 compliant HS so there may be more protocol-based pitfalls. You can also find the output of the device descriptor etc from USBView in my SW/USBView_broken.txt
EDIT 1: I have found finally some concrete error in the STM32 behavior. The DMAADDR is set for EPIN 0x81, and never increments, despite the DMA being enabled. I have went through literally every occurrence of the word "DMA" in the USB_OTG periphery.
I thought it might be that my linker script makes my array be stored in DTCM or similar, and the OTG DMA can't access it, but the address of txBuffer is 0x2003EBEC which is in SRAM2. The AHB matrix in the reference manual clearly shows, that the USB OTG HS DMA is master for a bus that SRAM2 is a slave of. And DTCM is connected too. I will look for application notes for USB OTG HS DMA - it just seems to be refusing to copy data!
I have fixed my issue by disabling the DMA setting. I have re-read the relevant portions of the reference manual and still don't know how exactly the values propagate into the Tx FIFOs. It is possible that DMA-less operation will be a major bottleneck in my project, I might return to this later.

In Application Programming issue

I'm working on project on STM32L152RCT6, where i have to build a mechanism to self update the code from the newly gated file(HEX file).
For that i have implemented such mechanism like boot loader where it checks for the new firmware if there it it has to cross verify and if found valid it has to store on "Application location".
I'm taking following steps.
Boot loader address = 0x08000000
Application address = 0x08008000
Somewhere on specified location it has to check for new file through Boot loader program.
If found valid it has to be copy all the HEX on location(as per the guide).
Than running the application code through jump on that location.
Now problem comes from step 5, all the above steps I've done even storing of data has been done properly(verify in STM32 utility), but when i'm jump to the application code it won't work.
Is there i have to cross check or something i'm missing?
Unlike other ARM controllers that directly jump to address 0 at reset, the Cortex-M series takes the start address from a vector table. If the program is loaded directly (without a bootloader), the vector table is at the start of the binary (loaded or mapped to address 0). First entry at offset 0 is the initial value of the stack pointer, second entry at address 4 is called the reset vector, it contains the address of the first instruction to be executed.
Programs loaded with a bootloader usually preserve this arrangement, and put the vector table at the start of the binary, 0x08008000 in your case. Then the reset vector would be at 0x08008004. But it's your application, you should check where did you put your vector table. Hint: look at the .map file generated by the linker to be sure. If it's indeed at 0x08008000, then you can transfer control to the application reset vector so:
void (*app)(void); // declare a pointer to a function
app = *(void (**)(void))0x08008004; // see below
app(); // invoke the function through the pointer
The complicated cast in the second line converts the physical address to a pointer to a pointer to a function, takes the value pointed to it, which is now a pointer to a function, and assigns it to app.
Then you should manage the switchover to the application vector table. You can do it either in the bootloader or in the application, or divide the steps between them.
Disable all interrupts and stop SysTick. Note that SysTick is not an interrupt, don't call NVIC_DisableIRQ() on it. I'd do this step in the bootloader, so it gets responsible to disable whatever it has enabled.
Assign the new vector table address to SCB->VTOR. Beware that the boilerplate SystemInit() function in system_stm32l1xx.c unconditionally changes SCB->VTOR back to the start of the flash, i.e. to 0x08000000, you should edit it to use the proper offset.
You can load the stack pointer value from the vector table too, but it's tricky to do it properly, and not really necessary, the application can just continue to use the stack that was set up in the bootloader. Just check it to make sure it's reasonable.
Have you changed the application according to the new falsh position?
For example the Vector Table has to be set correctl via
SCB->VTOR = ...
When your bootloader starts the app it has to configure everything back to the reset state as the application may relay on the default reset values. Espessially you need to:
Return values of all hardware registers to its reset values
Switch off all peripheral clocks (do not forget about the SysTick)
Disable all enabled interrupts
Return all clock domains to its reset values.
Set the vector table address
Load the stack pointer from the beginning of the APP vector table.
Call the APP entry point.(vertor table start + 4)
Your app has to be compiled and linked using the custom linker script where the FLASH start point is 0x8008000
for example:
FLASH (rx) : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 32K
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
where FLASH_BASE's value must be equal to the address of your IROM's value in KEIL
example:
#define FLASH_BASE 0x08004000
Keil configuration

How to boot STM32 from user flash?

STM32 microcontrollers are capable to boot from different sources such as:
User-Flash
System-memory
Embedded-SRAM.
On the firmware side, does "boot from user Flash" means executing a custom bootloader?
No.
The "Boot from User Flash" mode means that the application code that will be run after reset is located in user flash memory. The user flash memory in that mode is aliased to start at address 0x00000000 in boot memory space. Upon reset, the top-of-stack value is fetched from address 0x00000000, and code then begins execution at address 0x00000004.
In contrast, the "Boot from System Memory" mode simply means that the system memory (not the user flash) is now aliased to start at address 0x00000000. The application code in this case must have already been loaded into system memory.
The "Boot from Embedded SRAM" mode does not alias the SRAM address. When this mode is selected, the device expects the vector table to have been relocated using the NVIC exception table and offset register, and execution begins at the start of embedded SRAM. The application code in this case must have already been loaded into embedded SRAM.
For more details, refer to the Reference Manual for the specific family of STM32 devices you are using, in the section titled "Boot Configuration".
It depends.
The option "Boot from user Flash" will run whatever is in the user flash. This code could be anything you want. It could be:
a custom bootloader or
it could be application code.
The distinction is a logical one based on what you write your code to do. i.e. it is even possible to have an app that rewrites part or all of itself (what you call it is up to you).
If you do use a custom bootloader then you will normally have two projects.
The custom bootloader will have its own projects with its own generated binary image loaded into the start of flash.
The application code also having its own project and generated .bin file.
The application is loaded into a specific address that the bootloader knows about when it was built (in some free statically allocated memory block - normally on page boundaries to allow for reflashing while keeping the bootloader unchanged). These addresses can be configured in linker files.
Custom bootloaders are a great way of allowing features like:
A custom coms stack, to reflash your application via some other coms protocol.
Dual redundancy of the application code.
Note the STM32 micros "System Memory" already contains ST's own bootloader which supports a range of serial links to reflash the micro without needing a fully custom bootloader.
ST's documentation is stupid. They mention this, but they don't also tell that you need to only configure BOOT0 & BOOT1 pins in order to select the boot source.
So these two pins binary speaking give you three options that are:
(A) BOOT0 = 0, BOOT1 = whatever,
(B) BOOT0 = 1, BOOT1 = 0 and
(C) BOOT0 = 1, BOOT1 = 1.
Option A boots in FLASH, option B boots in bootloader and option C boots in SRAM.
So how to use this. First choose configuration B to start communicating with the bootloader to whom you instruct (in bootloader's own commands) to erase FLASH and upload your program inside FLASH. Then you change the configuration to A and reboot using MCU's RESET pin.
Note:
I perfer the NXP's documentation which has everything black on white.
As a developper I value my time and good documentation is a way to go.
Ditch ST and go for NXP if documentation is what you value. Here is NXP's sample documentation:
https://www.nxp.com/docs/en/user-guide/UM10562.pdf
I am really sorry ST, but you have to do better than what you are currently doing...
STM MCUs are a bit stupid in this regard. You need to configure the Option bytes in Flash so that your MCU will always run code from the user Flash after reset.
Run this code at the beginning of your main:
if ((FLASH->OPTR & FLASH_OPTR_nSWBOOT0_Msk) != 0x0 || ((FLASH->OPTR & FLASH_OPTR_nBOOT0_Msk) == 0x0))
{
while ((FLASH->SR & FLASH_SR_BSY_Msk) != 0x0) { ; }
FLASH->KEYR = 0x45670123;
while ((FLASH->SR & FLASH_SR_BSY_Msk) != 0x0) { ; }
FLASH->KEYR = 0xCDEF89AB;
while ((FLASH->SR & FLASH_SR_BSY_Msk) != 0x0) { ; }
FLASH->OPTKEYR = 0x08192A3B;
while ((FLASH->SR & FLASH_SR_BSY_Msk) != 0x0) { ; }
FLASH->OPTKEYR = 0x4C5D6E7F;
while ((FLASH->SR & FLASH_SR_BSY_Msk) != 0x0) { ; }
FLASH->OPTR = (FLASH->OPTR & ~(FLASH_OPTR_nSWBOOT0_Msk)) | FLASH_OPTR_nBOOT0_Msk;
while ((FLASH->SR & FLASH_SR_BSY_Msk) != 0x0) { ; }
FLASH->CR = FLASH->CR | FLASH_CR_OPTSTRT;
while ((FLASH->SR & FLASH_SR_BSY_Msk) != 0x0) { ; }
}

STM32: Booting and fetching vector table from SRAM

I would like to run my program from the SRAM region of the device.
It seemed quite clear to me, that I have to perform following steps:
Modify the vector table offset register SCB->VTOR (located at 0xE000ED08) to point to the beginning of the SRAM region, as that is where my vector table is located: 0x20000000
Reset the device so it fetches the stack pointer initialization value and the reset handler adress again.
Unfortunately, whenever I issue a reset init command in OpenOCD, the value of SCB->VTOR gets cleared. Hence, stack pointer initialization value and reset handler adress are fetched from 0x00000000 instead of 0x20000000.
Question
How do I get my STM32F4 to fetch the vector table from 0x20000000?
Just load the SP (MSP) from 0x20000000 (=VTOR) and the PC from 0x20000004 (=VTOR+4) manually.
The reset init command will usually reset the whole chip and no just the core - and VTOR will be initialized to zero even then.

entry() get into the different address from the entry point I set in the Elf

Recently I'm learning about the OS. And I want to write a simple bootloader, which change the real mode to protect mode and then load the simple kernel.
But I can't figure out the entry address problem.
At first I put the bootloader in the first sector of the OS.img(qemu), and then the kernel begin at the second sector.
Here's readelf result of my kernel:
The entry point address is 0x800c.
And the LMA and VMA are below:
A part of the bootloader which read elf-type kernel and then get into the entry(),which is the entry point address.
However, when I disassemble the bootloader, the entry() is below:
Call *0x8018, not *0x800c.
I don't know why this happen.
Could you please help me?
call *0x8018 performs a call to an address that is stored at 0x8018, that's correct since ELFHDR is 0x8000 and offset of e_entry in the header is 0x18.
The real problem is in the way you load segments into memory. Each segment should be loaded at address p_vaddr from file offset p_offset. Notice that in your case p_vaddr is 0x8000, that the same place in memory you loaded elf header to and that's why ELFHDR->e_entry gets overwritten. The easiest solution would be to load elf header at different address.
Source: http://www.skyfree.org/linux/references/ELF_Format.pdf