This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM6421: Help addressing SPI device MCP23S17 with MCSPI driver

Part Number: AM6421
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

Hello all, 

I am having trouble reading register values from the MCP23S17 SPI expander we are using with our AM6421B processor. To start with, we are using the MCSPI TI driver to address our SPI devices, including the MCP23S17. The main function for doing this comes from the iolink_master_demo in the industrial comms SDK version 9.2.0.8 named iolm_port_spi.c. This is the function:

int32_t IOLM_SPI_mcspiTransfer(
    uint32_t mcspiInstance,
    uint32_t mcspiChannel,
    uint32_t mcspiDataSize,
    uint8_t *pTxData,
    uint8_t *pRxData,
    uint32_t lengthInBytes)
{
    uint32_t           lengthInBits;
    uint32_t           lengthInWords;
    int32_t            error;
    MCSPI_Transaction *pTransaction;
    // check the platform
    MCSPI_Transaction transaction;
    pTransaction = &transaction;

    if ((mcspiInstance >= CONFIG_MCSPI_NUM_INSTANCES) || (mcspiChannel >= MCSPI_MAX_NUM_CHANNELS)
        || (gMcspiConfig[mcspiInstance].object == NULL))
    {
        error = SystemP_FAILURE;
        OSAL_error(
            __FILE__,
            __LINE__,
            OSAL_eERR_INVALIDSTATE,
            true,
            1,
            "SPI setup does not match sysCfg SPI setup or SPI init failed.\r\n");
        goto laExit;
    }

    /* convert length in bytes to frames with channel/instance configuration specific width */
    lengthInBits  = lengthInBytes * 8;
    lengthInWords = lengthInBits / mcspiDataSize;

    if ((lengthInBits % mcspiDataSize) > 0)
    {
        lengthInWords++;
    }

    MCSPI_Transaction_init(pTransaction);
    // load data to the cache
    if (MCSPI_OPER_MODE_DMA
        == ((MCSPI_Config *)gMcspiConfig[mcspiInstance].object->handle)->attrs->operMode)
    {
        CacheP_wb(pTxData, lengthInBytes, CacheP_TYPE_ALLD);
        CacheP_wbInv(pRxData, lengthInBytes, CacheP_TYPE_ALLD);
    }

    pTransaction->channel   = mcspiChannel;
    pTransaction->txBuf     = pTxData;
    pTransaction->rxBuf     = pRxData;
    pTransaction->dataSize  = mcspiDataSize;
    pTransaction->count     = lengthInWords;
    pTransaction->csDisable = TRUE;

    error = MCSPI_transfer(gMcspiConfig[mcspiInstance].object->handle, pTransaction);
laExit:
    return error;
}
If this is not the right way to address this device, then that would be a good place to start for fixing my issues. However, that's what I have been using thus far. 
I was unsure how to "set up" the device on initialization. It is my understanding that most of this is done in SysConfig generated code, but from looking elsewhere online it appeared there would also be initialization required to use the address pins (A2, A1, A0). On our board, we are using pin A2 as an address pin. Therefore, I have the following code to initialize the IOCON register to enable IOCON.HAEN:
  // Write to IOCON.HAEN
  // A2 is set here in the address - not sure if this is correct. 0A is 
  // the register address of IOCON when IOCON.BANK = 0.
  uint16_t txBuf[2] = {0x480Au, 0u};
  // Intended to set bit 3 in IOCON. 
  uint8_t u8txBuf = 0x08u;
  int32_t error = SystemP_SUCCESS;

  error = IOLM_SPI_mcspiTransfer(CONFIG_MCSPI_SPI1,
                                 MCSPI_CHANNEL_0,
                                 16u,
                                 txBuf,
                                 NULL,
                                 4u);

  DebugP_assert(error == SystemP_SUCCESS);

  error = IOLM_SPI_mcspiTransfer(CONFIG_MCSPI_SPI1,
                                 MCSPI_CHANNEL_0,
                                 8u,
                                 &utx8Buf,
                                 NULL,
                                 1u);


  DebugP_assert(error == SystemP_SUCCESS);
Next, I try to read from the GPIOA register with the following code:
  // 0x49 = address pin A2 set, and read 
  // 0x12 = address of GPIOA register when IOCON.BANK = 0.
  uint16_t txBuf = 0x4912;
  uint16_t rxBuf = 0u;
  int32_t error = SystemP_SUCCESS;

  error = IOLM_SPI_mcspiTransfer(CONFIG_MCSPI_SPI1,
                                 MCSPI_CHANNEL_0,
                                 16u,
                                 &txBuf,
                                 &rxBuf,
                                 3u);

  DebugP_assert(error == SystemP_SUCCESS);
Doing this results in reading the value "0xff 0xff". This is the expected value for reading the IODIR register, but that is at address register 0x0. We are attempting to address 0x12,  which should just contain "0x1" because we are powering pin 2 on the port of our board. The value returned is the same whether or not we try to initialize IOCON.HAEN, which would lead me to believe that we might be doing that incorrectly. 
This is the SysCfg we are using for MCSPI - the SPI expander (MCP23S17) is on CS0. 
mcspi1.intrEnable                  = "POLLED";
mcspi1.mode                        = "MULTI_CONTROLLER";
mcspi1.$name                       = "CONFIG_MCSPI_SPI1";
mcspi1.advanced                    = true;
mcspi1.SPI.$assign                 = "SPI1";
mcspi1.SPI.CLK.$assign             = "SPI1_CLK";
mcspi1.SPI.D0.rx                   = false;
mcspi1.SPI.D0.$assign              = "SPI1_D0";
mcspi1.SPI.D1.$assign              = "SPI1_D1";
mcspi1.child.$name                 = "drivers_mcspi_v0_mcspi_v0_template0";
mcspi1.mcspiChannel.create(2);
mcspi1.mcspiChannel[0].$name       = "CONFIG_MCSPI_SPI1_CS0";
mcspi1.mcspiChannel[0].advanced    = true;
mcspi1.mcspiChannel[0].CSn.rx      = false;
mcspi1.mcspiChannel[0].CSn.$assign = "SPI1_CS0";
mcspi1.mcspiChannel[1].$name       = "CONFIG_MCSPI_SPI1_CS1";
mcspi1.mcspiChannel[1].advanced    = true;
mcspi1.mcspiChannel[1].bitRate     = 20000000;
mcspi1.mcspiChannel[1].CSn.rx      = false;
mcspi1.mcspiChannel[1].CSn.$assign = "SPI1_CS1";
My question is - is there something I'm missing when addressing this SPI device? Is there some initialization I haven't done that needs to be done in order to properly read the registers? I apologize for such a long post, but we have been at this for a while and the most progress we got was reading "0xff 0xff" from the device. 
Thanks for any help,
Owen
  • Hi Owen,

    Thanks for your question.

    Allow me a day to go through this and follow up on this thread.

    Regards,

    Vaibhav

  • Hi Owen,

    Thanks for your patience.

    the most progress we got was reading "0xff 0xff" from the device. 

    This sort of indicates its just some dummy value, so either the connections or the SW code is the problem here.

    Lets take it step by step.

    Allow me sometime to go through the datasheet to understand the memory architecture of the Peripheral and how it tends to send or receive data.

    Post this I will follow up here on the thread.

    Regards,

    Vaibhav

  • Hi Vaibhav. Thank you for your prompt replies to this thread. Thankfully, I believe we figured out how to address the device. We currently have code that is reading values of the GPIO pins (we are using GPIOA for RX) on the MCP23S17 that reflect reality. The issue, I believe, was we were not sending enough bits to the device and they were not in the right format. The code I posted about modifying IOCON.HAEN was unnecessary, since it is still working as intended despite that code being commented out. We did not need to do any extra initialization for the MCP23S17 in our own code. The SysCfg I pasted in this thread appeared to work, although I would like to increase the frequency on Channel 0 to a higher value (I have not tested that yet). 

    This is the code we used to read the GPIOA and GPIOB registers (they come in the rxBuf together):

      uint32_t txBuf = 0x49120000;
      uint32_t rxBuf = 0u;
      int32_t error = SystemP_SUCCESS;
      bool iqState = false;
    
      error = IOLM_SPI_mcspiTransfer(CONFIG_MCSPI_SPI1,
                                     MCSPI_CHANNEL_0,
                                     32u,
                                     &txBuf,
                                     &rxBuf,
                                     4u);

    In this code, 0x49 corresponds to a READ of address pin A2 at register address 0x12. 0x12 is the address of the GPIOA register when IOCON.BANK = 0 (this is default).