Hi,
I have a SPI slave device which outputs 8-bit registers that I have to assemble. For example, I receive two 8-bit registers, a high and a low register, which I have to combine to get the ID-value I need. The code looks like this:
/** * @brief Read a CAN message. */ void can_readmsg(can_msg_t * can_msg) { uint16_t ret_value; ret_value = mcp2515_read(MCP_CANINTF); uint8_t m_tx_buf; uint8_t m_rx_buf[14]; ///< 1 empty response during MCP_READ_RX# and 13 registers. switch( (ret_value & (MCP_RX0IF | MCP_RX1IF)) ) { case MCP_RX0IF: m_tx_buf = MCP_READ_RX0; break; case MCP_RX1IF: m_tx_buf = MCP_READ_RX1; break; case (MCP_RX0IF | MCP_RX1IF): m_tx_buf = MCP_READ_RX0; break; default: m_tx_buf = 0; break; } if (m_tx_buf) { do {} while (!spi_xfer_done); spi_xfer_done = false; nrf_drv_spi_transfer(&c_spi, &m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_rx_buf)); if ( !((uint32_t)m_rx_buf[2] & MCP_RXB_IDE_M) ) { can_msg->id = ((uint32_t)m_rx_buf[1] << 3) | ((uint32_t)m_rx_buf[2] >> 5); } else { can_msg->eid = 1; can_msg->id = ( ((uint32_t)m_rx_buf[2] & 0x0003) << 16) | ((uint32_t)m_rx_buf[3] << 8) | ((uint32_t)m_rx_buf[4]); } can_msg->len = ((uint32_t)m_rx_buf[5] & MCP_DLC_MASK); for (uint8_t i = 0; i < can_msg->len; i++) { can_msg->data[i] = m_rx_buf[i + 6]; } } }
Now if I run it, I get the correct values in m_rx_buf, but the assembled values are not correct and remain always the same. I know this has something to do with 8-bit registers on a 32-bit system and integer promotion, but I cannot figure out how to get it right.
What I tried so far:
- Casting the array members in the shift operation, as shown in the code.
- Creating a uint32_t id_high, assigning it the value of the m_rx_buf[1] and then shifting it in a second step.
- Using memcpy to copy the bits of m_rx_buf[1] to id_high.
All these things result in the same incorrect values, sometimes simply 0, sometimes I get random bits. Does anyone know how to do this correctly?
Thanks!