CCM failed at MICSTATUS check

Hello Nordic team,

I'm developing a proprietary radio protocol and I'm using CCM peripheral for on-the-fly encryption. The packets seem to be correctly encrypted and decrypted at receiving site. However the MICSTATUS register is almost always set on 0. CRC is always correct. I succeeded to receive packet with valid MIC only when I decrease MAXPACKETSIZE to small values for tests, even when packet was trimmed to smaller size MIC was correct, but this looks like coincidence.

I'm using SEGGER Embedded Studio v6.32a with SEGGER compiler without softdevice. Hardware is nRF52840 Dongles

I have example arrays of data which i'm transmitting in loop:

uint8_t buffer1[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sollicitudin varius nulla, sed accumsan turpis tristique eget. In vestibulum ante sit amet urna pharetra consectetur. Praesent pulvinar sollicitudin augue at pellentesque. Integer lao.";
uint8_t buffer2[] = "Solaris was originally developed as proprietary software, but Sun Microsystems was an early commercial proponent of open source software and in June 2005 released most of the Solaris codebase under the CDDL license.";
uint8_t buffer3[] = "ABCDE";
uint8_t buffer4[] = "Bluetooth 5, IEEE 802.15.4-2006, 2.4 GHz transceiver";
uint8_t buffer5[] = "Why this is so hard?";
uint8_t buffer6[] = "Deoxyribonucleic acid is a polymer composed of two polynucleotide chains that coil around each other to form a double helix.";

Results vary depending on MAXPACKETSIZE register value.

MAXPACKETSIZE = 240

Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 243): Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sollicitudin varius nulla, sed accumsan turpis tristique eget. In vestibulum ante sit amet urna pharetra consectetur. Praesent pulvinar sollicitudin augue at pellentesque. I
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 216): Solaris was originally developed as proprietary software, but Sun Microsystems was an early commercial proponent of open source software and in June 2005 released most of the Solaris codebase under the CDDL license.
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 6): ABCDE
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 53): Bluetooth 5, IEEE 802.15.4-2006, 2.4 GHz transceiver
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 21): Why this is so hard?
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 125): Deoxyribonucleic acid is a polymer composed of two polynucleotide chains that coil around each other to form a double helix.

MAXPACKETSIZE = 150

Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 243): Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sollicitudin varius nulla, sed accumsan turpis tristique eget. In vestibulum ante s
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 216): Solaris was originally developed as proprietary software, but Sun Microsystems was an early commercial proponent of open source software and in J
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 6): ABCDE
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 53): Bluetooth 5, IEEE 802.15.4-2006, 2.4 GHz transceiver
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 21): Why this is so hard?
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 125): Deoxyribonucleic acid is a polymer composed of two polynucleotide chains that coil around each other to form a double helix.

MAXPACKETSIZE = 50 (all packet has valid MIC, but they are cut to max size)

Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 243): Lorem ipsum dolor sit amet, consectetur adipi
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 216): Solaris was originally developed as proprieta
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 6): ABCDE
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 53): Bluetooth 5, IEEE 802.15.4-2006, 2.4 GHz tran
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 21): Why this is so hard?
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 125): Deoxyribonucleic acid is a polymer composed o

MAXPACKETSIZE = 25 (this is the best, only one packet always has invalid MIC)

Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 243): Lorem ipsum dolor si
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 216): Solaris was original
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 6): ABCDE
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 53): Bluetooth 5, IEEE 80
Packet received from [5BF942E2][MIC: 0][CRC: 1] (Length: 21): Why this is so hard?
Packet received from [5BF942E2][MIC: 1][CRC: 1] (Length: 125): Deoxyribonucleic aci

I'm using this method to begin transmission (after setModeTx() is code responsible for receiving ACK):

int Radio::transmitPacket(uint32_t radioAddress, const uint8_t *buffer, uint8_t length, uint32_t &timeToAck) {
    int returnValue;

    // Current packet ID
    const uint8_t pid = this->nextPid++;

    // Limit payload size to max. packet size (minus headers)
    if (length > 243) {
        length = 243;
    }

    returnValue = length;

    // Packet type
    this->txBuffer[0] = PacketType::DATA;
    
    // Packet length (+ headers length)
    this->txBuffer[1] = length + 5;

    // Packet ID
    this->txBuffer[2] = pid;

    // Sender address and prefix is set once in constructor

    // Header CRC
    //this->txBuffer[8] = this->getCRC(txBuffer, 8);

    // Copy data to send
    memcpy(&this->txBuffer[8], buffer, length);

    // Configure recipient address
    NRF_RADIO->BASE0 = radioAddress;
    NRF_RADIO->PREFIX0 = (0xAA << RADIO_PREFIX0_AP0_Pos) | (0x00 << RADIO_PREFIX0_AP1_Pos) | (this->broadcastGroup << RADIO_PREFIX0_AP2_Pos);

    // Set pointer to unencrypted data buffer for encryption (max 257 bytes)
    NRF_CCM->INPTR = (uint32_t)&this->txBuffer;

    // Set pointer to encrypted data buffer for transmission
    NRF_CCM->OUTPTR = (uint32_t)&this->txBufferEncrypted;

    // Configure AES encryption
    NRF_CCM->MODE = CCM_MODE_MODE_Encryption << CCM_MODE_MODE_Pos | CCM_MODE_DATARATE_2Mbit << CCM_MODE_DATARATE_Pos | CCM_MODE_LENGTH_Extended << CCM_MODE_LENGTH_Pos;

    // Enable shortcut between event ENDKSGEN and task CRYPT
    NRF_CCM->SHORTS = (CCM_SHORTS_ENDKSGEN_CRYPT_Enabled << CCM_SHORTS_ENDKSGEN_CRYPT_Pos);

    // Start keystream generation
    NRF_CCM->TASKS_KSGEN = CCM_TASKS_KSGEN_TASKS_KSGEN_Trigger;

    // Set pointer to encrypted data buffer for transmission
    NRF_RADIO->PACKETPTR = (uint32_t)&this->txBufferEncrypted;

    // Set ACK timeout timer to 2ms
    NRF_TIMER2->CC[0] = 2000;

    // Clear events
    NRF_TIMER2->EVENTS_COMPARE[0] = 0;
    NRF_EGU0->EVENTS_TRIGGERED[0] = 0;
    NRF_EGU0->EVENTS_TRIGGERED[1] = 0;

    // Start transmission
    this->setModeTx();

    // Start ACK timeout timer
    NRF_TIMER2->TASKS_START = 1;

    // Listening mode will be called in interrupt after transmission END

    // Wait for response or timeout
    while (NRF_TIMER2->EVENTS_COMPARE[0] == 0 && NRF_EGU0->EVENTS_TRIGGERED[0] == 0 && NRF_EGU0->EVENTS_TRIGGERED[1] == 0);

    //ccmData.counter++;

    NRF_TIMER2->TASKS_CAPTURE[0] = 1;
    timeToAck = NRF_TIMER2->CC[0];
    NRF_TIMER2->TASKS_CLEAR = 1;

    // ACK timeout, retry
    if (NRF_TIMER2->EVENTS_COMPARE[0] == 1) {
        this->setModeIdle();
        return RadioError::ERROR_TIMEOUT;
    }

    // Check packet PID
    uint8_t *radioPacket = this->peekCurrentRxPacket();
    if (radioPacket[2] != pid) {
        return RadioError::ERROR_PID_MISMATCH;
    }

    // NACK received
    if (NRF_EGU0->EVENTS_TRIGGERED[1] == 1) {
        return RadioError::ERROR_NACK;
    }

    // ACK received
    if (NRF_EGU0->EVENTS_TRIGGERED[0] == 1) {
        return RadioError::ERROR_OK;
    }

    return returnValue;
}

inline void Radio::setModeIdle() {
    if (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) {
        NRF_RADIO->TASKS_DISABLE = 1;
    }
    
    this->radioState = RadioState::IDLE;
    while(NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled);
}

inline void Radio::setModeRx() {
    if (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) {
        this->setModeIdle();
    }

    // Set pointer to encrypted data buffer for decryption
    NRF_CCM->INPTR = (uint32_t)&this->rxBufferEncrypted;

    // Set pointer to unencrypted data buffer to store
    NRF_CCM->OUTPTR = (uint32_t)&this->rxBuffer[this->rxBufferHead];

    // Configure AES decryption
    NRF_CCM->MODE = CCM_MODE_MODE_Decryption << CCM_MODE_MODE_Pos | CCM_MODE_DATARATE_2Mbit << CCM_MODE_DATARATE_Pos | CCM_MODE_LENGTH_Extended << CCM_MODE_LENGTH_Pos;

    // Disable shortcut between event ENDKSGEN and task CRYPT
    NRF_CCM->SHORTS = (CCM_SHORTS_ENDKSGEN_CRYPT_Disabled << CCM_SHORTS_ENDKSGEN_CRYPT_Pos);

    // Enable PPI channel between EVENTS_ADDRESS and TASKS_CRYPT
    NRF_PPI->CHENSET = (PPI_CHENSET_CH25_Set << PPI_CHENSET_CH25_Pos);

    // Set pointer to encrypted data buffer for receiving
    NRF_RADIO->PACKETPTR = (uint32_t)&this->rxBufferEncrypted;

    // Start keystream generation
    NRF_CCM->TASKS_KSGEN = CCM_TASKS_KSGEN_TASKS_KSGEN_Trigger;

    // Configure device address
    NRF_RADIO->BASE0 = this->radioAddress;
    NRF_RADIO->PREFIX0 = (0xAA << RADIO_PREFIX0_AP0_Pos) | (0x00 << RADIO_PREFIX0_AP1_Pos) | (this->broadcastGroup << RADIO_PREFIX0_AP2_Pos);

    // Enable RADIO in RX mode
    NRF_RADIO->TASKS_RXEN = 1;
    this->radioState = RadioState::RX;
}

inline void Radio::setModeTx() {
    if (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) {
        this->setModeIdle();
    }

    // Disable PPI channel between EVENTS_ADDRESS and TASKS_CRYPT
    NRF_PPI->CHENCLR = (PPI_CHENSET_CH25_Set << PPI_CHENSET_CH25_Pos);

    // Enable RADIO in TX mode
    NRF_RADIO->TASKS_TXEN = 1;
    this->radioState = RadioState::TX;
}

Radio and CCM init:

Radio::Radio(const uint32_t radioAddress, const BroadcastGroup broadcastGroup): radioAddress(radioAddress), broadcastAddress(0xFFAAFF55), broadcastGroup(broadcastGroup) {
    // The peripheral and its registers will be reset to its initial state by switching the peripheral off and then back on again.
    NRF_RADIO->POWER = RADIO_POWER_POWER_Disabled << RADIO_POWER_POWER_Pos;
    NRF_RADIO->POWER = RADIO_POWER_POWER_Enabled << RADIO_POWER_POWER_Pos;

    // Configure radio with 2Mbit Nordic proprietary mode
    NRF_RADIO->MODE = RADIO_MODE_MODE_Nrf_2Mbit << RADIO_MODE_MODE_Pos;

    // Initialize whitening value
    NRF_RADIO->DATAWHITEIV = 0x55;

    // Configure device address Base0 + Prefix0
    NRF_RADIO->BASE0 = radioAddress;
    NRF_RADIO->PREFIX0 = (0xAA << RADIO_PREFIX0_AP0_Pos) | (0x00 << RADIO_PREFIX0_AP1_Pos) | (this->broadcastGroup << RADIO_PREFIX0_AP2_Pos);

    // Configure broadcast address Base0 + Prefix0
    NRF_RADIO->BASE1 = this->broadcastAddress;

    // Use logical address 0 (BASE0 + PREFIX0[0])
    NRF_RADIO->TXADDRESS = 0 << RADIO_TXADDRESS_TXADDRESS_Pos;

    // Use logical address 0 as RX address, and logical address 1 and 2 as broadcast RX address
    if (broadcastGroup == 0) {
        NRF_RADIO->RXADDRESSES = (RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos) | (RADIO_RXADDRESSES_ADDR1_Enabled << RADIO_RXADDRESSES_ADDR1_Pos);
    } else {
        NRF_RADIO->RXADDRESSES = (RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos) | (RADIO_RXADDRESSES_ADDR1_Enabled << RADIO_RXADDRESSES_ADDR1_Pos) | (RADIO_RXADDRESSES_ADDR2_Enabled << RADIO_RXADDRESSES_ADDR2_Pos);
    }

    // Initialize CRC (two bytes)
    NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos) | (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos);
    NRF_RADIO->CRCPOLY = 0x0000AAAA;
    NRF_RADIO->CRCINIT = 0x12345678;

    // Enable fast rampup
    NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_DTX_Center << RADIO_MODECNF0_DTX_Pos) | (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos);

    // +8dBm output power, sending packets at 2400MHz
    NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Pos8dBm << RADIO_TXPOWER_TXPOWER_Pos;

    // Configure packet with 8-bit S0 and S1, 8-bit length fields and 8-bit preamble.
    NRF_RADIO->PCNF0 = (1 << RADIO_PCNF0_S0LEN_Pos) | (8 << RADIO_PCNF0_S1LEN_Pos) | (RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos) | (8 << RADIO_PCNF0_LFLEN_Pos) | (RADIO_PCNF0_CRCINC_Include << RADIO_PCNF0_CRCINC_Pos) | (RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos);

    // Configure maximum payload length of 255 bytes, 5 bytes address, little endian with whitening enabled.
    NRF_RADIO->PCNF1 =  (255 << RADIO_PCNF1_MAXLEN_Pos) | (0 << RADIO_PCNF1_STATLEN_Pos) | (4  << RADIO_PCNF1_BALEN_Pos) | (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | (RADIO_PCNF1_WHITEEN_Enabled << RADIO_PCNF1_WHITEEN_Pos);

    // Configure shortcuts to:
    // - start as soon as READY event is received
    // - disable radio as soon RX or TX operation is END
    // - start RRSI measure on ADDESS event
    // - stop RRSI measure as soon RX or TX operation is END
    NRF_RADIO->SHORTS = (RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos) | 
                        (RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos) | 
                        (RADIO_SHORTS_ADDRESS_RSSISTART_Enabled << RADIO_SHORTS_ADDRESS_RSSISTART_Pos) |
                        (RADIO_SHORTS_DISABLED_RSSISTOP_Enabled << RADIO_SHORTS_DISABLED_RSSISTOP_Pos);

    // Timer 2 in timer mode and 32 bit resolution
    NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;
    NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_32Bit;

    // Configure shortcuts to CLEAR and STOP timer on COMPARE event
    NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos) | (TIMER_SHORTS_COMPARE0_STOP_Enabled << TIMER_SHORTS_COMPARE0_STOP_Pos);

    // Timer 2 clock is set to 1 MHz (f = 16 MHz / (2 ^ PRESCALER)). Interval between timer tick would be 1 / 1 MHz = 1us
    NRF_TIMER2->PRESCALER = 4;

    // Confdigure Radio interrupts
    NRF_RADIO->INTENSET = (RADIO_INTENSET_END_Enabled << RADIO_INTENSET_END_Pos); // | (RADIO_INTENSET_CRCOK_Enabled << RADIO_INTENSET_CRCOK_Pos);

    // Set sender address in tx buffer
    this->txBuffer[3] = (this->radioAddress & 0xFF);
    this->txBuffer[4] = ((this->radioAddress >> 8) & 0xFF);
    this->txBuffer[5] = ((this->radioAddress >> 16) & 0xFF);
    this->txBuffer[6] = ((this->radioAddress >> 24) & 0xFF);

    // Set sender prefix in tx buffer
    this->txBuffer[7] = 0xAA;

    // Set last packet id
    this->nextPid = 0;

    // Init RX queue circular buffer
    this->rxBufferHead = 0;
    this->rxBufferTail = 0;
    this->rxBufferDataSize = 0;

    // Set pointer to data buffer
    NRF_RADIO->PACKETPTR = (uint32_t)&this->rxBuffer[this->rxBufferHead];

    // Build CRC table
    this->buildCRCTable();

    // Enable encryption module
    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled << CCM_ENABLE_ENABLE_Pos;
    NRF_CCM->MAXPACKETSIZE = 25;
    
    // Pointer to data area used for temporary storage
    NRF_CCM->SCRATCHPTR = (uint32_t)&ccmScratchArea;

    // Init CCM data
    const char key[] = {0x1D, 0xF9, 0x2F, 0xA7, 0x9F, 0x2A, 0x1C, 0xF8, 0xBE, 0x3D, 0x8F, 0xE3, 0xD2, 0x53, 0xDA, 0x07};
    const char iv[] = {0x47, 0xC7, 0xCE, 0xD3, 0x2E, 0x92, 0xA4, 0x26};
    ccmData.counter = 0;
    ccmData.direction = 0;
    memcpy(ccmData.key, key, sizeof(ccmData.key));
    memcpy(ccmData.iv, iv, sizeof(ccmData.iv));

    // Pointer to data structure holding the AES key and the NONCE vector
    NRF_CCM->CNFPTR = (uint32_t)&ccmData;

    // Enable Radio interrupts
    NVIC_SetPriority(RADIO_IRQn, 1);
    NVIC_ClearPendingIRQ(RADIO_IRQn);
    NVIC_EnableIRQ(RADIO_IRQn);
}

Receiving part:

extern "C" void RADIO_IRQHandler(void) {
    if (NRF_RADIO->EVENTS_END) {
        // Packet received
        if (radio.getRadioState() == RadioState::RX) {
            // Packet header
            uint8_t *radioPacket = radio.peekCurrentRxPacket();
            const PacketType packetType = (PacketType)*radioPacket;
            const uint8_t packetLength  = *(radioPacket + 1) - 5;
            const uint8_t packetId = *(radioPacket + 2);
            const uint32_t senderAddress = (*(radioPacket + 6) << 24) | (*(radioPacket + 5) << 16) | (*(radioPacket + 4) << 8) | *(radioPacket + 3);
            //const uint8_t senderPrefix = *(radioPacket + 7);
            const uint8_t *payloadBuffer = (radioPacket + 8);
            //const uint32_t rssi = NRF_RADIO->RSSISAMPLE;

            // Calculate header CRC
            //const uint8_t crcCheck = radio.getCRC(radioPacket, 8);

            const bool crcOk = (/*crcCheck == headerCrc &&*/ NRF_RADIO->CRCSTATUS == RADIO_CRCSTATUS_CRCSTATUS_CRCOk);

            if(NRF_CCM->EVENTS_ERROR) logger.error("Decrypt error");

            // Get Message integrity check status
            const bool integrityCheck = (NRF_CCM->MICSTATUS == (CCM_MICSTATUS_MICSTATUS_CheckPassed << CCM_MICSTATUS_MICSTATUS_Pos));

            if (integrityCheck && crcOk) {
                logger.info("Packet received from [%X][MIC: %d][CRC: %d] (Length: %d): %s", senderAddress, integrityCheck, crcOk, packetLength, payloadBuffer);
            } else {
                logger.warning("Packet received from [%X][MIC: %d][CRC: %d] (Length: %d): %s", senderAddress, integrityCheck, crcOk, packetLength, payloadBuffer);
            }
            

            // Add RSSI value to packet
            *(radioPacket + 256) = (uint8_t)(NRF_RADIO->RSSISAMPLE & 0xFF);

            // Add "broadcast" flag to packet
            *(radioPacket + 257) = (bool)(NRF_RADIO->RXMATCH != 0);

            // Free fields
            //*(radioPacket + 258) = 0x00;
            //*(radioPacket + 259) = 0x00;

            radio.sendAck(senderAddress, packetId);
            return;

            // If packet was send to device address, not brodcast
            if (NRF_RADIO->RXMATCH == 0) {
                if (packetType == PacketType::ACK) {
                    NRF_EGU0->TASKS_TRIGGER[0] = EGU_TASKS_TRIGGER_TASKS_TRIGGER_Trigger;
                } else if (packetType == PacketType::NACK) {
                    NRF_EGU0->TASKS_TRIGGER[1] = EGU_TASKS_TRIGGER_TASKS_TRIGGER_Trigger;
                } else if (packetType == PacketType::DATA) {
                    if (radio.isRxBufferFull()) {
                        // Send NACK if process queue is full
                        radio.sendNack(senderAddress, NackReason::DEVICE_BUSY, packetId);
                    } else if (!crcOk) {
                        // Send NACK if packet has incorrect CRC
                        radio.sendNack(senderAddress, NackReason::CRC_ERROR, packetId);
                    } else if (!integrityCheck) {
                        // Send NACK if packet has failed integrity check
                        radio.sendNack(senderAddress, NackReason::MIC_ERROR, packetId);
                    } else {
                        // Add packet to process queue
                        radio.advanceRxBufferPointer();

                        // Send ACK if packet is correct
                        radio.sendAck(senderAddress, packetId);
                    }
                }
            } else {
                if (crcOk && integrityCheck && radio.isRxBufferFull() == false) {
                    // Add packet to process queue
                    radio.advanceRxBufferPointer();
                }
                radio.startReceiving();
            }
        // Packet sended
        } else if (radio.getRadioState() == RadioState::TX) {
            // Set TX end event
            NRF_EGU0->EVENTS_TRIGGERED[2] = EGU_TASKS_TRIGGER_TASKS_TRIGGER_Trigger;

            // Return to receiving mode
            radio.startReceiving();
        }

        NRF_RADIO->EVENTS_END = 0;
    }
}

What can cause such behavior? How I can get correct MIC status? I will be very grateful for every hint.

Parents
  • I just notice, that when I set CRC to disabled (zero bytes), MIC is always valid. Is CRC and MIC are in conflict somehow?

    CRC is on docs schematics, so it looks like it can be used with encryption.

  • I checked with all CRC setting 8, 16 and 24bit, only difference make if I disable CRC completely. I don't understand why this is behave this way.

  • That is odd, what I do know in general is that the CCM module have only been designed and qualifed with BLE in mind, so it could be that when used with proprietary nRF there is something occuring. Though have you tried to use the example on github as-is, does it happen then? Is there any difference if you use BLE 1Mbit mode instead of 1Mbit nRF mode?

    Kenneth

  • I just run the example from github. It works, but example uses Zephyr, I don't (also my code is based on interrupts) so it's hard to do any direct comparison. Anyway, it shows that CCM can work with proprietary mode with 2Mbit speed, in example MICSTATUS is validated.

    I also check what happen when I change mode to BLE_2Mbit, it's kind a worked, but transmission was unreliable and most of a time data was distorted, MIC field and CRC was never both "1". I'm not sure what requirements this mode has.

    I also tests almost all radio settings one by one, whitening, slower speed, preamble length, address length, S0 and S1 length, etc. Only MAXPACKETSIZE and CRC has any impact on MIC field. When MAXPACKETSIZE was smaller, MIC field was valid often as I described in first post, and when I disable CRC, then MIC is always valid but i don't have CRC.

    I can upload my code to Github if that will be any help.

  • It's getting weird now. I just found that when I set static payload to number of bytes in CRC, then MIC is valid, even when CRC is enabled. Somehow this extra space for CRC making MIC work.

    Does anyone understand where this behavior comes from?

    From what I understood from the documentation, the CRC is added at the end, regardless of the payload length. Whereas the MIC is added as an "extra payload". How can they conflict with each other?

  • At the moment most of the designers are on vacation, so I am not able to get their comment whether there are some combinations of requirements that needs to be satisfied. Until they are back my best suggestion is to still work on following the github repo I shared earlier as close as possible.

    Kenneth

Reply Children
Related