--fill command on PIC32MX boot flash memory - c

I have been trying for the last few weeks to find out why this isn't working. I have tried reading all the documentation I could find on my PIC32 MCU (PIC32MX795F512L) and the XC32 compiler I am using (v1.34) but with no success as of yet.
I need a special constant value written to the physical boot flash address 0x1FC02FEC (Virtual address: 0x9FC02FEC). This constant is 0x3BDFED92.
I have managed to successfully do this on my main program (If I program my pic32 directly using Real ICE) by means of the following command line (Which I put in xc32-ld under "Additional options" under the Project Properties):
--fill=0x3bdfed92#0x9FC02FEC
I am then able to check (Inside my main program) if this address indeed does have the correct value stored inside it, and this works too. I use the following code for that:
if(*(int *)(0x9fc02fec) == 0x3bdfed92)
My problem is the following. I do not want my main program hex file to write the constant into that location. I want my bootloader hex file to do this and my main program must just be able to read that location and see if that constant is there. If I use the --fill command inside the xc32-ld of my bootloader program, it successfully writes the constant just like the main program did (I have tested this by running my bootloader program with the same --fill command in debug mode and checking the 0x1FC02FEC address for the constant). Problem is, when my bootloader reads in a new main program via the MicroSD, and then jumps to the new main program, everything doesn't work. Seems like, before it jumps to the new main program, something bad happens and everything crashes. Almost like writing a value to the 1FC02FEC location is a problem when the program jumps from boot loader to main program.
Is there a reason for this? I hope my explanation is ok, if not then please let me know and I will try reword it in a more understandable way.
I am using the example code provided by Microchip to do the bootloader using the MicroSD card. The following is the code:
int main(void)
{
volatile UINT i;
volatile BYTE led = 0;
// Setup configuration
(void)SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
InitLED();
TRISBbits.TRISB14 = 0;
LATBbits.LATB14 = 0;
ClrWdt();
// Create a startup delay to resolve trigger switch bouncing issues
unsigned char x;
WORD ms = 500;
DWORD dwCount = 25;
while(ms--)
{
ClrWdt();
x=4;
while(x--)
{
volatile DWORD _dcnt;
_dcnt = dwCount*((DWORD)(0.00001/(1.0/GetInstructionClock())/10));
while(_dcnt--)
{
#if defined(__C32__)
Nop();
Nop();
Nop();
#endif
}
}
}
if(!CheckTrigger() && ValidAppPresent())
{
// This means the switch is not pressed. Jump
// directly to the application
JumpToApp();
}
else if(CheckTrigger() && ValidAppPresent()){
if(MDD_MediaDetect()){
if(FSInit()){
myFile = FSfopen("image.hex","r");
if(myFile == NULL){
JumpToApp();
}
}
else{
JumpToApp();
}
}
else{
JumpToApp();
}
}
//Initialize the media
while (!MDD_MediaDetect())
{
// Waiting for media to be inserted.
BlinkLED();
}
// Initialize the File System
if(!FSInit())
{
//Indicate error and stay in while loop.
Error();
while(1);
}
myFile = FSfopen("image.hex","r");
if(myFile == NULL)// Make sure the file is present.
{
//Indicate error and stay in while loop.
Error();
while(1);
}
// Erase Flash (Block Erase the program Flash)
EraseFlash();
// Initialize the state-machine to read the records.
record.status = REC_NOT_FOUND;
while(1)
{
ClrWdt();
// For a faster read, read 512 bytes at a time and buffer it.
readBytes = FSfread((void *)&asciiBuffer[pointer],1,512,myFile);
if(readBytes == 0)
{
// Nothing to read. Come out of this loop
// break;
FSfclose(myFile);
// Something fishy. The hex file has ended abruptly, looks like there was no "end of hex record".
//Indicate error and stay in while loop.
Error();
while(1);
}
for(i = 0; i < (readBytes + pointer); i ++)
{
// This state machine seperates-out the valid hex records from the read 512 bytes.
switch(record.status)
{
case REC_FLASHED:
case REC_NOT_FOUND:
if(asciiBuffer[i] == ':')
{
// We have a record found in the 512 bytes of data in the buffer.
record.start = &asciiBuffer[i];
record.len = 0;
record.status = REC_FOUND_BUT_NOT_FLASHED;
}
break;
case REC_FOUND_BUT_NOT_FLASHED:
if((asciiBuffer[i] == 0x0A) || (asciiBuffer[i] == 0xFF))
{
// We have got a complete record. (0x0A is new line feed and 0xFF is End of file)
// Start the hex conversion from element
// 1. This will discard the ':' which is
// the start of the hex record.
ConvertAsciiToHex(&record.start[1],hexRec);
WriteHexRecord2Flash(hexRec);
record.status = REC_FLASHED;
}
break;
}
// Move to next byte in the buffer.
record.len ++;
}
if(record.status == REC_FOUND_BUT_NOT_FLASHED)
{
// We still have a half read record in the buffer. The next half part of the record is read
// when we read 512 bytes of data from the next file read.
memcpy(asciiBuffer, record.start, record.len);
pointer = record.len;
record.status = REC_NOT_FOUND;
}
else
{
pointer = 0;
}
// Blink LED at Faster rate to indicate programming is in progress.
led += 3;
mLED = ((led & 0x80) == 0);
}//while(1)
return 0;
}

If I remember well (very long time ago I used PIC32) you can add into your linker script:
MEMORY
{
//... other stuff
signature (RX) : ORIGIN = 0x9FC02FEC, length 0x4
}
then
SECTIONS
{
.signature_section:
{
BYTE(0x3b);
BYTE(0xdf);
BYTE(0xed);
BYTE(0x92);
}>signature
}
Googling around I also found out, that you could do that in your source code, I hope...
const int __attribute__((space(prog), address(0x9FC02FEC))) signature = 0x3bdfed92;

In my program I use an attribute to place a certain value at a certain location in memory space. My bootloader and App can read this location. This may be a simpler way for you to do this. This is using xc16 and a smaller part but I've done it on a PIC32 as well.
#define CHECK_SUM 0x45FB
#define CH_HIGH ((CHECK_SUM & 0xFF00) >> 8)
#define CH_LOW ((CHECK_SUM & 0x00FF) >> 0)
const char __attribute__((space(prog), address(APP_CS_LOC))) CHKSUM[2] = {CH_LOW,CH_HIGH};
Just a note, when you read it, it will be in the right format: HIGH->LOW

Related

Fixing a Memory Overwrite errors likely due to malloc on an STM32 Nucleo-F334R8

I hope this is a clear explanation of my issue I've been runnign around various manuals for a little over a week now tryign to solve this:
Recently I have been redesigning a software design for a class project after feedback and testing on the STM32 Nucleo-F334R8(my initial code was riddled with memory and timing errors)
Currently I run into two main errors:
(This issue has been resolved)
I had been using sprintf not accounting for the trailing null character writting outside of allocated memory.
When processing USART Data using USART 1 in Asynchronous mode at
115200 Baudrate:
Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in
memset ()
Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in
memset ()
Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in
memset ()
Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in
memset ()
Program received signal SIGTRAP, Trace/breakpoint trap. 0x080056b4 in
std.isra ()
The value stored at the address 0x08002c08 in question is usually very
large typically something like 134228385 in decimal. Also if I
forcefully step through the issue the program continues to run fine
and never encounters the problem again which I find strange
possible cause?
UPDATE: So
I've traced the memset issue around a bit and found that it occurs
during my setOutputBuffer method:
String>,%5d,%8s,%3d,%3d,%3d,%4d,%4d,%4d,%10.6f,%11.6f,%7.1f,%3d,%3.1f\n",uptime,timeString,temperature,pressure,humidity,acc1,acc2,acc3,latitude,longitude,altitude,current,voltage);
} ``` Which leads me to believe the issue lies in finding a value that
is being used to set the Output buffer message.
I would like advice on how to further troubleshoot these two issues
and whether there is a chance that the memset error is related the
later bss error.
My String Tokenizing code(edited):
```c void tokenize(char* in){ const char *p = in; const char
delim[] = ","; char *token = NULL; uint8_t n = 0;
do{
size_t length = strcspn(p, delim); if(length > 0){ if(token ==
NULL){
token = malloc(sizeof(char)*length); // create memory space for the token
memset(token, 0, length); // ensure initialized memory is blank
sprintf(token, "%.*s",(int)length,p); // store the token from a substring of Input Buffer
p+=length; // move pointer to next ','
parseToken(token, n); // extract information from the token be it latitude, longitude etc
memset(token, 0, length); // clear the token
free(token); // free up the token's spot in memory
token = NULL; // set token pointer to null
n++; }
}
}while(*((++p)+1) != '*'); // The expected string ends with a
checksum character '*' after the last ',' } ``` I've re-examined the
function and made a lot of changes now I can successfully step through
the entire function without issue, the program then returns to my main
loop, and I let it run for a while but then I suddenly run back into
the same memset issue, even without receiving any bytes over USART
here is the code for my main loop and the subsequent function calls it
makes:
```c
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (byteFlag){ byteRecieved(); byteFlag = 0; }
if(msgFlag){ msgRecieved(); msgFlag = 0; }
if(secFlag){ setOutputBuffer(); HAL_UART_Transmit(&huart1,
(uint8_t *)bufferOut, 91, 1000); secFlag = 0; }
} ``` byteReceived: ```c if((char) byteIn == '$'){
clearInputBuffer(); } else if((char) byteIn == '\n'){
msgFlag = 1; }
else{ storeChar(); } ```
msgReceived: ```c if(isValid()){ if (checksum()) {
tokenize(bufferIn); clearInputBuffer(); } } ```
isValid: ```c char substr[5]; strncpy(substr, (bufferIn+1), 5);
if(!strcmp(substr, "GPGGA")){ return 1; }
return 0; ```
checksum: ```c int checksum(){ int calc_checksum = 0; int
in_checksum; int i = 0; char checkstr[2]; uint8_t hasCheckSum = 0;
for(int j = 0; j<91; j++){ if (bufferIn[j] == '*') { hasCheckSum
= 1; i = 1; } }
if (hasCheckSum) { while (bufferIn[i] != '*'){ calc_checksum ^=
bufferIn[i]; i++; } checkstr[0] = bufferIn[i+1]; checkstr[1]
= bufferIn[i+2]; } else {return 0;}
in_checksum = parseStr_HexToInt(checkstr);
if (calc_checksum == in_checksum){ return 1; } else { return 0;
} } ```
clearInputBuffer: ```c void clearInputBuffer(){ int i = 0;
for(i = 0; i < 100; i++){ bufferIn[i] = ' '; } bufferIn[0] = '$';
} ```
(This issue has been resolved)
Essentially the source of my problem was misuse of sprintf and overwritting program code with null characters
I encountered a breakpoint trap while filling the bss segment of the
board's memory
And after adding Seven GPIO Ports for a 4bit mode LCD(namely PA12,
PA11, PB12, PB11, PB2, PB1, PB15) and two for a two channel ADC in DMA
mode (PA1, PA0):
Program received signal SIGTRAP, Trace/breakpoint trap.
LoopFillZerobss () at ..\startup/startup_stm32f334x8.s:103 103 cmp r2,
r3 While trying to implement LCD and ADC functionality I receive the breakpoint trap error during the LoopFillZerobss function of
startup which proved fatal, particularly by stopping my USART
from reporting at all(however it can still receive bytes as
interrupt and process tokens etc, just refuses to transmit), After
reading up into the bss segment I attempted to solve the issue by
initializing as many global variables as I could to non-zero values,
this did not work, the problem is observed after adding the
STM32CubeMx settings for ADC and the 7 GPIO pins used in the LCD,
however none of these use unitialized variables to my knowledge
unless the predefined code generated by CubeMX is going beyond the
bounds of the bss segment of memory and that the size of the bss
segment is too large now for the board's memory (which I suspect is
unlikely but can't rule out).
Essentially the idea of this project is to receive various data over USART, ADC and later I2C and display various aspects of the data over USART and LCD at currently if I discard the ADC and LCD errors my USART code functions as the memset() error is non-lethal but I suspect that leaving it there is only causing me later issues but I'm also not sure where to fix my tokenizing code, assuming it is the root of my issues.
Essentially the source of my problem was misuse of sprintf and overwritting program code with null characters
By ensuring to use snprintf rather than sprintf with well defined sized strings I ran into no more memory issues.

Probably a pointer issue but not sure why

This is going to be a bit abstract due to the specific ARM (LPCXpresso 1115R/303) Cortex M0 and the H6 bluetooth module, and with NXP software there are a ton of driver files that are linked so hopefully the code snip below will be enough to identify the problem.
I am creating a simple menu system through bluetooth. Everything works with communcation. I send the message from the board, it is visible on the phone, I respond and print the value in the console of the program. All are exactly what I want them to be. But this is what happens:
1) start debug session and resume
2) 1st menu sends to phone, correct.
3) Type response to phone and send, correct.
4) message appears in console exactly as entered from phone (Just the number 1 appears)
5) Have if loop that checks to see if Buffer value == '1';
6) must not == 1 because it never enters the loop.
7) reprints the value of the buffer, and it still equals 1.
The only hint I have is a warning that says "makes integer from pointer without a cast [-Wint-conversion]" on the assignment line as indicated below.
void ArmPeripheral() {
UARTCount = 0;
LPC_UART->IER = IER_THRE | IER_RLS; /* Disable RBR */
UARTSend( (uint8_t *)menu1, sizeof(menu1));
LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR; /* Re-enable RBR */
while(1) {
if(UARTCount != 0){
printf("%s 1st print\n",UARTBuffer);
int bVal = UARTBuffer; // This is where the error occurs, tried uint8_t, did not work.
printf("%s This is bVal\n",bVal);
if(bVal == 1) { //have tried 1, '1', and "1" none work
printf("inside loop %s...\n",UARTBuffer);
printf("%s This is bVal\n",bVal);
LEDControl();
}
printf("%s second print\n",UARTBuffer);
UARTCount = 0;
}
}
}
enter image description here
Nevermind, it was just a simple pointer issue. UARTBuffer is a external volatile uint8_t in the UART.c file, and even though it is not defined as a pointer, it is pointing to a buffer somehow.
int bVal = *UARTBuffer;
if(bVal == '1') {
The above worked, but if anyone has any more in depth information that could explain why I would be interested in knowing. This is how I initialized the buffer:
extern volatile uint32_t UARTCount;
extern volatile uint8_t UARTBuffer[BUFSIZE];

ARM USB functions take too long to excecute

I just started working on a XMC4500 microcontroller. I'm currently implementing USB CDC communication and I ran into a problem.
After calling a function "USBD_VCOM_SendData" the program then waits for a frame to send the data.
More accurately the program waits in the "usbd_endpoint_stream_xmc4000.c" file in the "Endpoint_Write_Stream_LE". There it waits for the endpoint to be ready in the "Endpoint_WaitUntilReady()" function.
#define USB_STREAM_TIMEOUT_MS 100
uint8_t Endpoint_WaitUntilReady(void)
{
#if (USB_STREAM_TIMEOUT_MS < 0xFF)
uint8_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
#else
uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS;
#endif
uint16_t PreviousFrameNumber = USB_Device_GetFrameNumber();
for (;;)
{
if (Endpoint_GetEndpointDirection() == ENDPOINT_DIR_IN)
{
if (Endpoint_IsINReady())
{
return ENDPOINT_READYWAIT_NoError;
}
}
else
{
if (Endpoint_IsOUTReceived())
{
return ENDPOINT_READYWAIT_NoError;
}
}
uint8_t USB_DeviceState_LCL = USB_DeviceState;
if (USB_DeviceState_LCL == DEVICE_STATE_Unattached)
{
return ENDPOINT_READYWAIT_DeviceDisconnected;
}
else if (USB_DeviceState_LCL == DEVICE_STATE_Suspended)
{
return ENDPOINT_READYWAIT_BusSuspended;
}
else if (Endpoint_IsStalled())
{
return ENDPOINT_READYWAIT_EndpointStalled;
}
uint16_t CurrentFrameNumber = USB_Device_GetFrameNumber();
if (CurrentFrameNumber != PreviousFrameNumber)
{
PreviousFrameNumber = CurrentFrameNumber;
if (!(TimeoutMSRem--))
{
return ENDPOINT_READYWAIT_Timeout;
}
}
}
}
This wait time is approximately 100-150us and is to long. When I was working on STM32 microcontrollers the execution time was significantly smaller.
Has anybody delt with this problem before?
Is there a way to write the data to a buffer and then let the peripheral take care of the transaction without the need for processor time?
Or at least trigger an interrupt when the endpoint is ready for the transaction.
The loop terminates instantly if Endpoint_IsINReady() returns true. Perhaps you should try to run that macro in your code, and only send messages to the USB host if it evaluates to true.
Also, to ensure that the library does not use its blocking behavior, you'll have to think about how much data the endpoint buffers can hold at once, and make sure you don't send any more than that at a time. (You can make your own buffer and send it to the USB library piecemeal if you need to.)

How can the index in this code snippet ever reach 2154? (gcc, embedded C, ARM Cortex M0)

I'm writing a driver for a GSM modem running on an ARM Cortex M0. The only UART on the system is in use for talking to the modem, so the best I can do for logging the UART conversation with the modem is to build up a string in memory and watch it with GDB.
Here are my UART logging functions.
// Max number of characters user in the UART log, when in use.
#define GSM_MAX_UART_LOG_CHARS (2048)
static char m_gsm_uart_log[GSM_MAX_UART_LOG_CHARS] = "";
static uint16_t m_gsm_uart_log_index = 0;
// Write a character to the in-memory log of all UART messages.
static void gsm_uart_log_char(const char value)
{
m_gsm_uart_log_index++;
if (m_gsm_uart_log_index > GSM_MAX_UART_LOG_CHARS)
{
// Clear and restart log.
memset(&m_gsm_uart_log, 0, GSM_MAX_UART_LOG_CHARS); // <-- Breakpoint here
m_gsm_uart_log_index = 0;
}
m_gsm_uart_log[m_gsm_uart_log_index] = value;
}
// Write a string to the in-memory log of all UART messages.
static void gsm_uart_log_string(const char *value)
{
uint16_t i = 0;
char ch = value[i++];
while (ch != '\0')
{
gsm_uart_log_char(ch);
ch = value[i++];
}
}
If I set a breakpoint on the line shown above, the first time it's reached, m_gsm_uart_log_index is already well over 2048. I've seen 2154 and a bunch of other values between 2048 and 2200 or so.
How is this possible? There's no other code that touches m_gsm_uart_log_index anywhere.
You have a buffer overflow happening which could trample on m_gsm_uart_log_index.
The check for end of buffers should be:
if (m_gsm_uart_log_index >= GSM_MAX_UART_LOG_CHARS) {
...
}
As it stands, m_gsm_uart_log_index can reach 2048, and so writing m_gsm_uart_log_index[2048] is likely to be at the location where m_gsm_uart_log_index is stored.
You are writing to the buffer when m_gsm_uart_log_index == GSM_MAX_UART_LOG_CHARS, which means that you are overrunning the buffer by 1 character. This writes into the first byte of m_gsm_uart_log_index and corrupts it.
Change:
if (m_gsm_uart_log_index > GSM_MAX_UART_LOG_CHARS)
to:
if (m_gsm_uart_log_index >= GSM_MAX_UART_LOG_CHARS)

C on embedded system w/ linux kernel - mysterious adc read issue

I'm developing on an AD Blackfin BF537 DSP running uClinux. I have a total of 32MB SD-RAM available. I have an ADC attached, which I can access using a simple, blocking call to read().
The most interesting part of my code is below. Running the program seems to work just fine, I get a nice data package that I can fetch from the SD-card and plot. However, if I comment out the float calculation part (as noted in the code), I get only zeroes in the ft_all.raw file. The same occurs if I change optimization level from -O3 to -O0.
I've tried countless combinations of all sorts of things, and sometimes it works, sometimes it does not - earlier (with minor modifications to below), the code would only work when optimization was disabled. It may also break if I add something else further down in the file.
My suspicion is that the data transferred by the read()-function may not have been transferred fully (is that possible, even though it returns the correct number of bytes?). This is also the first time I initialize pointers using direct memory adresses, and I have no idea how the compiler reacts to this - perhaps I missed something, here?
I've spent days on this issue now, and I'm getting desperate - I would really appreciate some help on this one! Thanks in advance.
// Clear the top 16M memory for data processing
memset((int *)0x01000000,0x0000,(size_t)SIZE_16M);
/* Prep some pointers for data processing */
int16_t *buffer;
int16_t *buf16I, *buf16Q;
buffer = (int16_t *)(0x1000000);
buf16I = (int16_t *)(0x1600000);
buf16Q = (int16_t *)(0x1680000);
/* Read data from ADC */
int rbytes = read(Sportfd, (int16_t*)buffer, 0x200000);
if (rbytes != 0x200000) {
printf("could not sample data! %X\n",rbytes);
goto end;
} else {
printf("Read %X bytes\n",rbytes);
}
FILE *outfd;
int wbytes;
/* Commenting this region results in all zeroes in ft_all.raw */
float a,b;
int c;
b = 0;
for (c = 0; c < 1000; c++) {
a = c;
b = b+pow(a,3);
}
printf("b is %.2f\n",b);
/* Only 12 LSBs of each 32-bit word is actual data.
* First 20 bits of nothing, then 12 bits I, then 20 bits
* nothing, then 12 bits Q, etc...
* Below, the I and Q parts are scaled with a factor of 16
* and extracted to buf16I and buf16Q.
* */
int32_t *buf32;
buf32 = (int32_t *)buffer;
uint32_t i = 0;
uint32_t n = 0;
while (n < 0x80000) {
buf16I[i] = buf32[n] << 4;
n++;
buf16Q[i] = buf32[n] << 4;
i++;
n++;
}
printf("Saving to /mnt/sd/d/ft_all.raw...");
outfd = fopen("/mnt/sd/d/ft_all.raw", "w+");
if (outfd == NULL) {
printf("Could not open file.\n");
}
wbytes = fwrite((int*)0x1600000, 1, 0x100000, outfd);
fclose(outfd);
if (wbytes < 0x100000) {
printf("wbytes not correct (= %d) \n", (int)wbytes);
}
printf(" done.\n");
Edit: The code seems to work perfectly well if I use read() to read data from a simple file rather than the ADC. This leads me to believe that the rather hacky-looking code when extracting the I and Q parts of the input is working as intended. Inspecting the assembly generated by the compiler confirms this.
I'm trying to get in touch with the developer of the ADC driver to see if he has an explanation of this behaviour.
The ADC is connected through a SPORT, and is opened as such:
sportfd = open("/dev/sport1", O_RDWR);
ioctl(sportfd, SPORT_IOC_CONFIG, spconf);
And here are the options used when configuring the SPORT:
spconf->int_clk = 1;
spconf->word_len = 32;
spconf->serial_clk = SPORT_CLK;
spconf->fsync_clk = SPORT_CLK/34;
spconf->fsync = 1;
spconf->late_fsync = 1;
spconf->act_low = 1;
spconf->dma_enabled = 1;
spconf->tckfe = 0;
spconf->rckfe = 1;
spconf->txse = 0;
spconf->rxse = 1;
A bfin_sport.h file from Analog Devices is also included: https://gist.github.com/tausen/5516954
Update
After a long night of debugging with the previous developer on the project, it turned out the issue was not related to the code shown above at all. As Chris suggested, it was indeed an issue with the SPORT driver and the ADC configuration.
While debugging, this error messaged appeared whenever the data was "broken": bfin_sport: sport ffc00900 status error: TUVF. While this doesn't make much sense in the application, it was clear from printing the data, that something was out of sync: the data in buffer was on the form 0x12000000,0x34000000,... rather than 0x00000012,0x00000034,... whenever the status error was shown. It seems clear then, why buf16I and buf16Q only contained zeroes (since I am extracting the 12 LSBs).
Putting in a few calls to usleep() between stages of ADC initialization and configuration seems to have fixed the issue - I'm hoping it stays that way!

Resources