This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Bitwise operations on uint8_t / Integer promotion

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!

Related