2
votes

Background I am working on an embedded application written in C using IAR Embedded Workbench IDE and toolchain which runs on an STM32F091 (ARM Cortex-M0 core) microcontroller. The application writes data to the microcontrollers embedded flash memory, into which only 32-bit words can be entered (perhaps half-words work also).

Problem description The data is stored in an uint8_t byte type array preceeded by some header information at the start (in this case an AT response code from an on-board modem) which should not be written to flash. I'd like to send a uint32_t pointer to to where in the uint8_t buffer the actual data starts. But if this offset is not 4 byte aligned, my application crashes since it tries to access an unaligned uint32_t type.

This describes what I'm trying to do (not the real code, just an example):

uint8_t modemResponseBuffer[MAX_MODEM_RESPONSE_SIZE];

/* Get the modem response data (including modem response header data) */
size_t modemResponseSize = GetModemResponseData(modemResponseBuffer);

/* Get the actual data size from the header information */
size_t dataSize = GetActualDataSizeFromModemResponseHeader(modemResponseBuffer);

/* Get the offset to where the actual data starts in the modem response */
size_t modemDataOffset = GetModemResponseDataOffset(modemResponseBuffer);

/* Write the data part of the response to embedded flash memory. 
The modemDataOffset can be any number which messes up 4 byte data alignment */
ProgramFlashMemory(DATA_FLASH_STORAGE_ADDRESS, (uint32_t*)&modemResponseBuffer[modemDataoffset],
 dataSize);

Inside the ProgramFlashMemory function, the FLASH_ProgramWord Standard Peripheral Library function is called in a loop.

Question(s) How do I solve this problem efficiently? I'm working on a system where I have limited amount of memory (32 kb RAM), so I would prefer not to copy the desired contents from the uint8_t buffer to a new buffer of uint32_t type. At the moment I've manually aligned the data byte by byte by looping through, but this seems rather clumsy to me. But I've yet to come up with a better solution and I am interested in what suggestions I might receive here.

Also, if someone has the knowledge, I also wonder why the application crashes in this case. What is the reason my core (or any core?) can't handle unaligned data types?

3
Do you need the header data? - alk
Well I need it to identify the type of data the application is receiving and the size of it. I'm sorry if that was unclear from the example I made to show the problem. - Stenis
Do you need the header after having written to the flash-memory? - alk
While wording my answer this question came to my mind: Are you sure ProgramFlashMemory () expects the number of bytes (uint8_t) and not the number of uint32_t? - alk
"... my application crashes since it tries to access an unaligned uint32_t type." from what do you conclude this? - alk

3 Answers

3
votes

Change ProgramFlashMemory() to take a void*, then internally cast that to a uint8_t*, which you then iterate taking four bytes at a time into a unit32_t which you then write to the flash.

The void* allows the address of any object to write without needing an explicit cast.

Something like:

int ProgramFlashMemory( uint32_t* addr, void* data, int length )
{
    int byte = 0 ;
    int word = 0 ;

    while( byte < length )
    {
        uint32_t flash_word = 0 ;

        // Copy four bytes to word
        // Note: little-endian byte order assumed,
        //       reverse for big-endian.  
        // If end is not aligned, fill with 0xff.
        for( b = 0; b < 4; b++ )
        {
            flash_word |= byte < length ? 
                          (uint8_t*)data[byte] << (b<<3) : 
                          0xFF ;
            byte++ ;
        }

        ProgramFlashWord( addr[word], flash_word ) ;
        word++ ;
    }

    // Return bytes written - may be linger than `length` by up-to 
    // three for end-alignment.
    return byte ;
}

You may want to keep the original ProgramFlashMemory() for efficient aligned writes, in which case perhaps ProgramFlashMemoryUnaligned(). Note that it is not just the alignment, but the length being not necessarily divisible by four that you need to take care of.

1
votes

This assumes the header data is not needed anymore after having written the payload data.

To make sure the buffer's alignment is correct you might want to declare it like this:

uint32_t modemResponseBuffer[(MAX_MODEM_RESPONSE_SIZE * sizeof (uint8_t) / sizeof (uint32_t)) + 1];

Just move the payload data to the beginning of the buffer prior to calling the writer-function:

memmove(modemResponseBuffer, modemResponseBuffer + modemDataoffset, dataSize);

Please note that memcpy() would not work here as destination and source overlap.

Then call the writer like this:

ProgramFlashMemory(DATA_FLASH_STORAGE_ADDRESS, modemResponseBuffer, dataSize);
1
votes

The reason the ARM Cortex-M0 core crashes on the unaligned access is because that's what it's designed to do. Taking the hard fault exception is actually an improvement over some older cores which would access the value incorrectly and then continue executing with the corrupt value. Some newer ARM cores do have limited hardware support for unaligned accesses.

Here are a copule of suggestions.

Redesign ProgramFlashMemory() so that it accepts a uint8_t* rather than a uint32_t*. In order to program words it should copy the individual bytes from the buffer into a local variable which has the proper alignment. Then write the local variable copy to flash.

Redesign GetModemResponseData() so that it parses the header as the header is being read from the stream. It will determine the length of the header and the starting point of the data before the data is read from the stream. When the stream is at the start of the data it should begin copying the data into a fresh buffer that is separate from the header and properly aligned.