Tool/software: TI C/C++ Compiler
Hello,
As the title shows, I am consistently getting an IMPRECISERR that causes a fault on the processor and (under debug conditions) abort code to be executed and the registers to be dumped in the console as shown below.
[Cortex_M4_0] usFault: IMPRECISERR: Delayed Bus Fault, exact addr unknown, address: e000ed38 Exception occurred in background thread at PC = 0x00002da4. Core 0: Exception occurred in ThreadType_Task. Task name: {unknown-instance-name}, handle: 0x20001bc0. Task stack base: 0x20001c10. Task stack size: 0x800. R0 = 0x0d000148 R8 = 0x20004d7c R1 = 0x0000000e R9 = 0x20001b80 R2 = 0x00000000 R10 = 0x000186a0 R3 = 0x00000000 R11 = 0x0000c350 R4 = 0xffffffff R12 = 0x20002330 R5 = 0xffffffff SP(R13) = 0x20002358 R6 = 0xffffffff LR(R14) = 0x00009da5 R7 = 0x0000ffff PC(R15) = 0x00002da4 PSR = 0x01001000 ICSR = 0x00400803 MMFSR = 0x00 BFSR = 0x04 UFSR = 0x0000 HFSR = 0x40000000 DFSR = 0x00000001 MMAR = 0xe000ed34 BFAR = 0xe000ed38 AFSR = 0x00000000 Terminating execution...
The task stack base is pointing to the location of our main task loop stack, the same task that is calling a function we use for logging events on our product, which causes the failure. This segment of code was working properly with no issues when we were logging events on internal flash, but due to design considerations and our growing program size, we are implementing the log on an external SPI flash chip, the AT25SF041 from Adesto. Attached is the code for some of the relevant functions, as well as the disassembly of this function and the register/stack contents at various points of execution.
I have stepped through the disassembly and found the issue lies in that the processor is popping invalid data off of the stack into the PC and instead of returning back to our main task. This is then attempting execution of a memory location that is invalid, causing the fault. What I don't see is the relevant portion of the stack (what should be popped into our registers) being modified, or where this invalid memory location is coming from.
Another bit of information I have noticed is that if I comment out the last line of the C code that increments our indexing for the event log (EventLogPtr.lastEntry += log_entry_index), the code will succeed, but obviously our pointer never moves so we can't have a contiguous log, just one log entry that can be overwritten indefinitely. Another "fix" I've seen (which still leads to similar issues later) is that if you turn of code optimizations on this function, it will manage to execute properly. It isn't until a later usage of the same code that a similar issue arises, and I'd also like to avoid having to use #pragmas to save the day if possible.
From all of this my questions are - what exactly does this imprecise error mean? Is there anything in our relevant code that would point to a possible issue? Could this be a compiler based issue that is handling our code incorrectly?
Any tips or info on where to start/go next on debugging this issue would be greatly appreciated.
Regards,
Tyler Witt
struct event_log_ptr { uint32_t firstEntry; // "head" of event log - oldest event log entry (memory offset) uint32_t lastEntry; // "tail" of event log - current event log entry (memory offset) uint32_t lastUploaded; // Memory offset for end of last uploaded event uint16_t lastSeqNumber; // Last counter value used for sequential counter of entries } __attribute__((packed)); typedef struct event_log_ptr event_log_ptr; // Global Variables struct event_log_ptr EventLogPtr = {0,0,0,0}; /* * ======== LogEvent ======== * * This fxn will log an event to the event log * * uint8_t data_type = log type code for event entry * uint32_t rcid = user credential for action being logged * uint8_t data_len = extra data length * uint8_t *extra_data = pointer to extra data * * NOTE: THIS CODE REQUIRES THE AT25SF041 TO BE POPULATED * */ void LogEvent(uint8_t data_type, uint32_t rcid, uint8_t data_len, uint8_t *extra_data) { bool new_sector = FALSE; volatile uint8_t log_entry_index = 0; uint32_t pageOffset; GPFlashRow1Obj row1; // Test EventLogPtr for legitimacy - if out of range of event log entirely, reset them if (EventLogPtr.lastEntry >= XMEM_SECTOR_2 || EventLogPtr.firstEntry >= XMEM_SECTOR_2) { InitEventLogPtr(); } // If entry won't fit on this page, we need a new page pageOffset = (EventLogPtr.lastEntry >> 8) * XMEM_PAGE_SIZE; if( EventLogPtr.lastEntry + data_len + CRC_SIZE + sizeof(struct event_log_entry) >= XMEM_PAGE_SIZE) { // Set the lastEntry to the start of the next fresh page EventLogPtr.lastEntry = pageOffset + XMEM_PAGE_SIZE; // Last page offset plus size of page } // If new page is in new sector, then we need an erased sector, and we need to increment other pointers if (!(EventLogPtr.lastEntry & 0xFFF)) // lastEntry is on an even sector border, new sector required { new_sector = TRUE; // Do we need to wrap the log back around to the start of the event log? if ( EventLogPtr.lastEntry >= XMEM_LOG_SIZE) { EventLogPtr.firstEntry = EventLogPtr.firstEntry + XMEM_4kB_OFFSET; // Set firstEntry to start of next sector of flash if ( EventLogPtr.lastUploaded <= EventLogPtr.firstEntry && EventLogPtr.lastUploaded >= EventLogPtr.lastEntry) { // First entry advancing past the last uploaded entry means no entries in the log have been uploaded EventLogPtr.lastUploaded = EventLogPtr.firstEntry; // Set last uploaded entry to first entry if((lastUploadedOffset + LAST_UPLOADED_WITH_INDEX) > MAX_LAST_UPLOADED_OFFSET) // If entry won't fit... { reinitFlashMemory(); // Reinitialize flash so it is ready to go for the next entry } readFlashPg(FLASH_PAGE(GPFLASH_BASE),(BASE_LAST_UPLOADED_OFFSET + lastUploadedOffset),(uint8_t *)&row1.index,LAST_UPLOADED_WITH_INDEX); // Read the old index/value lastUploadedOffset = lastUploadedOffset + LAST_UPLOADED_WITH_INDEX; // Update offset row1.index++; // Update index row1.lastUploaded = EventLogPtr.lastUploaded; // Update Value writeFlashPg(FLASH_PAGE(GPFLASH_BASE),(BASE_LAST_UPLOADED_OFFSET + lastUploadedOffset),(uint8_t *)&row1.index,LAST_UPLOADED_WITH_INDEX); // Write new entry } EventLogPtr.lastEntry = XMEM_LOG_BASE; // Set lastEntry to zero offset from base of event log } // Have we previously wrapped around and need to bump the first entry forwards? if ( EventLogPtr.lastEntry == EventLogPtr.firstEntry ) { EventLogPtr.firstEntry = EventLogPtr.firstEntry + XMEM_4kB_OFFSET; // Set firstEntry to start of next page of flash // Do we need to wrap the firstEntry back to the start? if ( EventLogPtr.firstEntry >= XMEM_LOG_SIZE) { EventLogPtr.firstEntry = XMEM_LOG_BASE; } if ( EventLogPtr.lastUploaded <= EventLogPtr.firstEntry && EventLogPtr.lastUploaded >= EventLogPtr.lastEntry) { // First entry advancing past the last uploaded entry means no entries in the log have been uploaded EventLogPtr.lastUploaded = EventLogPtr.firstEntry; // Set last uploaded entry to first entry if((lastUploadedOffset + LAST_UPLOADED_WITH_INDEX) > MAX_LAST_UPLOADED_OFFSET) // If entry won't fit... { reinitFlashMemory(); // Reinitialize flash so it is ready to go for the next entry } readFlashPg(FLASH_PAGE(GPFLASH_BASE),(BASE_LAST_UPLOADED_OFFSET + lastUploadedOffset),(uint8_t *)&row1.index,LAST_UPLOADED_WITH_INDEX); // Read the old index/value lastUploadedOffset = lastUploadedOffset + LAST_UPLOADED_WITH_INDEX; // Update offset row1.index++; // Update index row1.lastUploaded = EventLogPtr.lastUploaded; // Update Value writeFlashPg(FLASH_PAGE(GPFLASH_BASE),(BASE_LAST_UPLOADED_OFFSET + lastUploadedOffset),(uint8_t *)&row1.index,LAST_UPLOADED_WITH_INDEX); // Write new entry } } } // If we are using a new sector, make sure it is clean if ( new_sector ) { xmemWake(); // Wake up the thing and wait a bit xmemSendOpCode(XMEM_WRITE_ENABLE, NO_ADDRESS, 0); // Enable external memory to be written xmemSendOpCode(XMEM_BLOCK_ERASE_4K, EventLogPtr.lastEntry, 0); // Clear this page out xmemPowerDown(); // Put external memory in Power Down mode } ++EventLogPtr.lastSeqNumber; // Increment the sequence number uint32_t temp = 0; // For transporting data to log_entry array // Fill log entry data log_entry[log_entry_index++] = data_len; // Write the extra data length log_entry[log_entry_index++] = data_type; // Write new log entry temp = EventLogPtr.lastSeqNumber; // Get sequence number log_entry[log_entry_index++] = (uint8_t) temp; // LSByte First log_entry[log_entry_index++] = (uint8_t) (temp >> 8); // MSByte Last temp = getRTC_epoch(); // Get time log_entry[log_entry_index++] = (uint8_t) temp; // LSByte First log_entry[log_entry_index++] = (uint8_t) (temp >> 8); log_entry[log_entry_index++] = (uint8_t) (temp >> 16); log_entry[log_entry_index++] = (uint8_t) (temp >> 24);// MSByte Last log_entry[log_entry_index++] = (uint8_t) rcid; // RCID - LSByte First log_entry[log_entry_index++] = (uint8_t) (rcid >> 8); log_entry[log_entry_index++] = (uint8_t) (rcid >> 16); log_entry[log_entry_index++] = (uint8_t) (rcid >> 24);// MSByte Last // Append Xdata if necessary for(temp = 0; temp < data_len; temp++) { log_entry[log_entry_index++] = *extra_data; // Add data extra_data++; // Point to next byte } // Run the whole CRC, append it to the entry EventCRCInit(); eventCRC = ComputeCRC16(&log_entry[0], log_entry_index,CRC16_PRESET); log_entry[log_entry_index++] = (uint8_t) eventCRC; log_entry[log_entry_index++] = (uint8_t) (eventCRC >> 8); // Write log entry to Flash xmemWake(); // Wake up the thing and wait a bit xmemSendOpCode(XMEM_WRITE_ENABLE, NO_ADDRESS, 0); // Enable external memory to be written xmemWrite(EventLogPtr.lastEntry,&log_entry[0],log_entry_index); // Write it to the external memory xmemPowerDown(); // Put external memory in Power Down mode // Push lastEntry forward EventLogPtr.lastEntry += log_entry_index; } Disassembly: ___________________________________________________________________________ Beginning of function: LogEvent(): 00002abc: E92D41FF push.w {r0, r1, r2, r3, r4, r5, r6, r7, r8, lr} 361 if (EventLogPtr.lastEntry >= XMEM_SECTOR_2 || EventLogPtr.firstEntry >= XMEM_SECTOR_2) 00002ac0: 4CBC ldr r4, [pc, #0x2f0] 00002ac2: 4EB9 ldr r6, [pc, #0x2e4] 356 volatile uint8_t log_entry_index = 0; 00002ac4: 2500 movs r5, #0 361 if (EventLogPtr.lastEntry >= XMEM_SECTOR_2 || EventLogPtr.firstEntry >= XMEM_SECTOR_2) 00002ac6: 462F mov r7, r5 00002ac8: F8D41006 ldr.w r1, [r4, #6] 356 volatile uint8_t log_entry_index = 0; 00002acc: F88D500A strb.w r5, [sp, #0xa] 361 if (EventLogPtr.lastEntry >= XMEM_SECTOR_2 || EventLogPtr.firstEntry >= XMEM_SECTOR_2) 00002ad0: 428E cmp r6, r1 00002ad2: D303 blo $C$L769 00002ad4: F8D40002 ldr.w r0, [r4, #2] 00002ad8: 4286 cmp r6, r0 00002ada: D203 bhs $C$L770 363 InitEventLogPtr(); $C$L769: 00002adc: F00CF848 bl #0xeb70 00002ae0: F8D41006 ldr.w r1, [r4, #6] 368 if( EventLogPtr.lastEntry + data_len + CRC_SIZE + sizeof(struct event_log_entry) >= XMEM_PAGE_SIZE) $C$L770: 00002ae4: F101000E add.w r0, r1, #0xe 00002ae8: 28FF cmp r0, #0xff 00002aea: D905 bls $C$L771 End of function: 466 xmemWake(); // Wake up the thing and wait a bit 00002d7a: F00FFC61 bl #0x12640 467 xmemSendOpCode(XMEM_WRITE_ENABLE, NO_ADDRESS, 0); // Enable external memory to be written 00002d7e: 2006 movs r0, #6 00002d80: F04F31FF mov.w r1, #-1 00002d84: F00BF9E2 bl #0xe14c 468 xmemWrite(EventLogPtr.lastEntry,&log_entry[0],log_entry_index); // Write it to the external memory 00002d88: F89D000A ldrb.w r0, [sp, #0xa] 00002d8c: F00BFE48 bl #0xea20 469 xmemPowerDown(); // Put external memory in Power Down mode 00002d90: F012FB1E bl #0x153d0 472 EventLogPtr.lastEntry += log_entry_index; 00002d94: F89D100A ldrb.w r1, [sp, #0xa] 00002d98: F8D40006 ldr.w r0, [r4, #6] 00002d9c: 1840 adds r0, r0, r1 00002d9e: F8C40006 str.w r0, [r4, #6] 00002da2: 9000 str r0, [sp] 00002da4: E8BD81FF pop.w {r0, r1, r2, r3, r4, r5, r6, r7, r8, pc} (Registers & Stack Contents:) Beginning of Function: PC 0x00002ABC Program Counter [Core] SP 0x20002380 General Purpose Register 13 - Stack Pointer [Core] LR 0x00002141 General Purpose Register 14 - Link Register [Core] xPSR 0x61000000 Stores the status of interrupt enables and critical processor status signals [Core] R0 0x02000000 General Purpose Register 0 [Core] R1 0x20004AE8 General Purpose Register 1 [Core] R2 0x2000D28C General Purpose Register 2 [Core] R3 0x02000000 General Purpose Register 3 [Core] R4 0x00000064 General Purpose Register 4 [Core] R5 0x00000000 General Purpose Register 5 [Core] R6 0x20004454 General Purpose Register 6 [Core] R7 0x000003E8 General Purpose Register 7 [Core] R8 0x20004D7E General Purpose Register 8 [Core] R9 0x20001B80 General Purpose Register 9 [Core] R10 0x000186A0 General Purpose Register 10 [Core] R11 0x0000C350 General Purpose Register 11 [Core] R12 0x00020BCC General Purpose Register 12 [Core] R13 0x20002380 General Purpose Register 13 [Core] R14 0x00002141 General Purpose Register 14 [Core] MSP 0x20013FF8 MSP Register [Core] PSP 0x20002380 PSP Register [Core] DSP 0x20002380 DSP Register [Core] CTRL_FAULT_BASE_PRI 0x02000000 CM4 Special Registers [Core] @0x200021E8 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 90 00 00 00 0C 4C 00 20 18 4C 00 20 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF C0 1B 00 20 B1 B4 00 00 58 49 00 20 C0 48 00 20 00 00 00 00 00 00 00 00 90 03 00 00 42 0D 02 00 EB D0 00 00 00 00 00 00 C0 48 00 20 57 A3 01 00 92 11 0A 00 58 49 00 20 90 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E3 82 01 00 00 00 00 00 3F 2A 00 00 00 00 00 00 00 00 00 00 07 00 00 FF 80 4A 5D 05 00 00 00 00 00 00 00 00 00 00 00 00 E8 4A 00 20 8C D2 00 20 80 4A 5D 05 5B 5C 67 05 00 00 00 00 00 00 02 00 F5 7D 01 00 30 23 00 20 E3 82 01 00 94 1B 00 20 94 1B 00 20 C0 1B 00 20 00 00 00 00 01 C3 00 20 00 00 00 02 00 00 00 00 07 00 00 FF 90 00 00 00 39 00 00 00 94 1B 00 20 64 00 00 00 00 00 00 00 54 44 00 20 E8 03 00 00 7E 4D 00 20 80 1B 00 20 A0 86 01 00 50 C3 00 00 F1 20 00 00 05 07 19 F9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 4A 5D 05 40 1F 00 00 10 27 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 7D FA 00 00 00 00 00 00 00 00 00 00 35 1E 00 00 7D FA 00 00 59 93 01 00 BE BE BE BE End of Function: PC 0x00002D94 Program Counter [Core] SP 0x20002358 General Purpose Register 13 - Stack Pointer [Core] LR 0x00009DA5 General Purpose Register 14 - Link Register [Core] xPSR 0x21000000 Stores the status of interrupt enables and critical processor status signals [Core] R0 0x00000001 General Purpose Register 0 [Core] R1 0x00000390 General Purpose Register 1 [Core] R2 0x00000000 General Purpose Register 2 [Core] R3 0x00000000 General Purpose Register 3 [Core] R4 0xFFFFFFFF General Purpose Register 4 [Core] R5 0xFFFFFFFF General Purpose Register 5 [Core] R6 0xFFFFFFFF General Purpose Register 6 [Core] R7 0x0000FFFF General Purpose Register 7 [Core] R8 0x20004D7C General Purpose Register 8 [Core] R9 0x20001B80 General Purpose Register 9 [Core] R10 0x000186A0 General Purpose Register 10 [Core] R11 0x0000C350 General Purpose Register 11 [Core] R12 0x20002330 General Purpose Register 12 [Core] R13 0x20002358 General Purpose Register 13 [Core] R14 0x00009DA5 General Purpose Register 14 [Core] MSP 0x20013FF8 MSP Register [Core] PSP 0x20002358 PSP Register [Core] DSP 0x20002358 DSP Register [Core] CTRL_FAULT_BASE_PRI 0x02000000 CM4 Special Registers [Core] @0x200021E8 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 10 00 00 00 00 FF FF FF FF 90 00 00 00 0C 4C 00 20 18 4C 00 20 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF C0 1B 00 20 B1 B4 00 00 58 49 00 20 9C DE 00 20 00 00 00 00 F0 0B 02 00 00 00 00 00 20 00 00 00 EB D0 00 00 00 00 00 00 9C DE 00 20 FD D7 00 00 35 1E 00 00 58 49 00 20 90 03 00 00 00 00 00 00 10 00 C2 04 00 00 00 00 E3 82 01 00 00 00 00 00 17 38 00 00 00 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 E0 00 20 2D 99 01 00 1B 80 00 00 6F BB 00 00 00 00 00 00 A3 08 07 00 00 E0 00 20 39 BB 00 00 F0 0B 02 00 E8 0B 02 00 48 0D 02 00 EC 0B 02 00 00 E0 00 20 A5 9D 00 00 00 00 00 00 00 00 00 00 30 23 00 20 C4 DF 00 20 40 DE 00 20 FF FF 00 00 7C 4D 00 20 80 1B 00 20 A0 86 01 00 3F 19 01 00 00 DE 00 20 FF FF FF FF FF FF FF FF 0D 54 01 00 00 BE BE BE 48 23 00 20 02 01 00 20 44 23 00 20 48 23 00 20 B9 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 95 2D 00 00 01 00 10 00 00 4A 00 20 57 1F 0E 20 00 00 00 02 64 00 00 00 00 00 00 00 54 44 00 20 E8 03 00 00 7E 4D 00 20 41 21 00 00 05 07 19 F9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 4A 5D 05 40 1F 00 00 10 27 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 7D FA 00 00 00 00 00 00 00 00 00 00 35 1E 00 00 7D FA 00 00 59 93 01 00 BE BE BE BE