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!