1

I have a strange problem here with my ESP8266 (Wemos D1 mini). I'm wrting a library for building a network with the nRF24L01 transmitter.

I have defined a gloabl uint8_t arry which represents my receive buffer. When receiving a transmission from an other device, the array gets filled. After filling the array, I start to parse the buffer, to identify if there is a valid Header/Frame. The header contains some typical data like sender, checksum... If the header is valid the data of frame gets parsed. The structure of the data is always the same. There can be x so called DataTriples. A DataTriple is a combination of Key (cstring), Type of Value (uint8_t) and the Value itself. The type of value can be basic types like INT8, UINT8 or FLOAT or STRING.

And now the stange thing.

To save memory I do not copy the values from the buffer into dedicated variables. I alway point to the positions in the buffer. And when I want to read a value, I do a simple pointer cast and read out the values. This is perfectly working if the value is a string or a simple 1 byte long uint8_t. But if it is a float or an uint32_t I get a LoadStoreAlignmentCause Excetion that's telling me, that I want to access not alligned memory. How can this be? The pointers are definitly pointing to the correct buffer positon. I checked this, because if I create a new float variable and do a memcpy from the buffer to the variables address, everything is good. But I a create a float pointer and point to the position in the buffer, I get a this exception.

Can somebody tell me the reason or tell me what I'm doing wrong?

Here are some code fragment, to get a better understanding.

bool SBSmartHomeBasicDevice::parseDataTriples() {
if (_IncommingTransmission) {
    uint8_t* iCurrentPos;
    uint8_t iDataTripleCount = 0;
    // _LastReceivedFrame.Payload points to the receive buffer
    for (iCurrentPos = _LastReceivedFrame.Payload; iCurrentPos < (_LastReceivedFrame.Payload + _LastReceivedFrame.Header.PayloadSize); iCurrentPos) {
        // Catch the type of the triple
        uint8_t type = *((uint8_t*)iCurrentPos);
        // increase the pointer about uint8_t size
        iCurrentPos += sizeof(uint8_t);
        // Catch the key of the triple
        char* key;
        key = (char*)(iCurrentPos);
        // increase the pointer about strlen of key + 1 
        iCurrentPos += strlen((char*)iCurrentPos) + 1;
        // catch the value
        void* value = (void*)(iCurrentPos);
        _LastReceivedTriples[iDataTripleCount].setType(type);
        _LastReceivedTriples[iDataTripleCount].setKey(key);


        // ***
        // Here starts the interesting part 
        // ***
        float* fTmp = (float*)iCurrentPos;
        // The following works perfect
        // ****
        float f;
        memcpy(&f, fTmp, sizeof(float));
        Serial.println(f);
        // ****
        // The following causes an exception
        Serial.println(*fTmp);
        // *** EXCEPTION ***


        _LastReceivedTriples[iDataTripleCount].setValue(iCurrentPos);
        // now increase the pointer
        switch (type) {
        case SMART_HOME_VALUE_TYPE_STRING:
            iCurrentPos += strlen((char*)iCurrentPos) + 1;
            break;
        case SMART_HOME_VALUE_TYPE_INT8:
        case SMART_HOME_VALUE_TYPE_UINT8:
            iCurrentPos += sizeof(int8_t);
            break;
        case SMART_HOME_VALUE_TYPE_INT16:
        case SMART_HOME_VALUE_TYPE_UINT16:
            iCurrentPos += sizeof(int16_t);
            break;
        case SMART_HOME_VALUE_TYPE_FLOAT:
            iCurrentPos += sizeof(float);
            break;
        case SMART_HOME_VALUE_TYPE_INT32:
        case SMART_HOME_VALUE_TYPE_UINT32:
            iCurrentPos += sizeof(int32_t);
            break;
        default:
            Serial.println("parseDataTriples(): Unknown ValueType");
        }
        _LastReceivedTriples[iDataTripleCount].print();
        iDataTripleCount++;
        _LastReceivedTriplesCount = iDataTripleCount;
    } 
    return true;
}
return false;

}

An Thanks a lot for taking the time and helping me.

Greets Schullebernd

2
  • Do you know what alignment is, and how it applies to memory accesses? Commented Nov 25, 2017 at 21:12
  • Thanks, after reading the answer from Codo I now know it more in detail. I never was confronted with such a problem and probably I'm a little bit spoiled by high level languages like C# and Java. Commented Nov 25, 2017 at 23:40

1 Answer 1

2

The ESP8266 can only read floats (and 16 bit ints, 32 bit ints, doubles) from properly aligned addresses, i.e. addresses that are a multiple of the data types. As float is 4 bytes long, it can only be read from an address that is a multiple of 4. Otherwise you get the mentioned exception.

You are working with a uint8_t array. uint8_t is 1 byte long and therefore does not need and probably is not aligned in any way. The array might start at address 170001. If you now have a float value at position 40 within the array, your code tries to read a float value from address 170041, which is not properly aligned and causes an exception.

The solution is to first copy the bytes for the float value to a local, properly aligned variable. That's what you do but then you access it again in the non-aligned location and get an exception.

    float* fTmp = (float*)iCurrentPos; // does not copy; takes a pointer to the orignal location

    float f;
    memcpy(&f, fTmp, sizeof(float)); // copies data to aligned variable

    Serial.println(f); // prints value from aligned variable

    Serial.println(*fTmp); // prints value for original, non-aligned location

Just get rid of the last line.

Sign up to request clarification or add additional context in comments.

1 Comment

Wow, youre completely right. I really didn't know that. I just tried it and I increased the length of the key in my data triple step by step and exaclty at the length, where the float value starts at an address in the buffer which is a multible of 4, the exception doesn't occure. Honestly this is a little bit wired. Do you have a link, where I can read more about this? And thank you very much, this cost me 4 houres of my life...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.