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.

TM4C1231E6PZ: SPI communication in slave mode

Part Number: TM4C1231E6PZ

Hi Team:

 My customer using TM4C1231E6PZ, and we have a question would like to ask. The TM4C1231E6PZ chip uses SPI communication and is used as a slave.
How to judge that the host has completed sending data?  Sent via DMA between master and slave.
Can it be determined using the functions uDMAChannelIsEnabled(MASTER_SSI_UDMA_RX_CHANNEL) and SSIBusy(MASTER_SSI_BASE)?

because we found the following issues:

The program code is as follows:
tem1 = (_Bool)((uDMAChannelIsEnabled(MASTER_SSI_UDMA_RX_CHANNEL))||(uDMAChannelIsEnabled(MASTER_SSI_UDMA_TX_CHANNEL)))
if((tem1 == (_Bool)false) )
{
uDMADisable();
……………………
}


It was found that the main SPI was still sending data, but the " if “ was true and the slave SPI turned off the interrupt.
As shown below, please help confirm whether there is a problem with customer`s program configuration? Please provide reference configuration. tks ~

for more details:

 

  • Hi,

    The TM4C1231E6PZ chip uses SPI communication and is used as a slave.
    How to judge that the host has completed sending data? 

      As a slave, it uses the SPICLK provided by the master as the reference clock to send and receive data. The slave has no way of knowing how many data the master is going to send. Say the master wants to send 10 words of data, it will generate the SPICLK and the data on MOSI. While receiving SPICLK, the slave will send the slave data on MISO. Only the master knows that it has 10 words to send, not the slave. The master can embed information onto a header byte containing the number of bytes of the data the master will send. But this is a system level protocol to be defined by the user. 

  • Hi Tsal:

     Many tks for the comments.

     today i have a visit with customer to dig out more details about this issue.

     i think there is a mistake for the previous description.

    C2=MOSI 

    C1=MISO

    C3 = sync up signal for master SPI ,when the master finish the DMA TX transfer , flip the C3 voltage level.(But slave SPI with not handle this signal)

    C4= the Slave master will detect the RX DMA status and follow below procedure:(target to make sure the slave SPI RX & TX DMA is done, then means the RX already receive all the data.)

    tem1 = (_Bool)((uDMAChannelIsEnabled(MASTER_SSI_UDMA_RX_CHANNEL))||(uDMAChannelIsEnabled(MASTER_SSI_UDMA_TX_CHANNEL)))
    if((tem1 == (_Bool)false) )
    {
    uDMADisable();
    ……………………

    //The time from detection to execution is 50us

    //flip the C4 voltage level
    }

    when the master SPI detect the C4 signal inversion with edge triggering, the master SPI will start enable DMA to send data. When it is done , flip the C3 voltage level, such a cycle.

    So base on above external pin for Sync logic , customer can reach the Point to point Full duplex TX/RX.

    But customer found some random issue is that the slave DMA will disable in advance when the MOSI still transmitting.

    For normal case ,all the signal have been fully accepted。

    The following is the initial code of the slave spi:

    void spi_init(void)
    { 
     /*lint -e718*/
     /********开始配置spi**************/	
      /*使能主机所在SSI端口 */
      SysCtlPeripheralEnable(MASTER_PERIPH_SSI);
      /*使能主机所在的GPIO端口*/
      SysCtlPeripheralEnable(MASTER_PERIPH_GPIO);
      /*GPIO数字功能选择SSI功能*/
      GPIOPinConfigure(MASTER_SSI_CLK_PIN);
      GPIOPinConfigure(MASTER_SSI_FSS_PIN);
      GPIOPinConfigure(MASTER_SSI_RX_PIN);
      GPIOPinConfigure(MASTER_SSI_TX_PIN);
      /*主机所在GPIO引脚设置*/
      GPIOPinTypeSSI(MASTER_GPIO_BASE,MASTER_GPIO_PINS);
    	
    //	GPIOPinTypeGPIOInput(GPIO_PORTA_BASE,MASTER_SSI_FSS_PIN);
    	
      /*主机所在SSI配置:片选低电平有效、时钟上升沿捕获数据,下降沿传输数据、主机模式、250khz、8位数据格式*/
      SSIConfigSetExpClk(MASTER_SSI_BASE,SysCtlClockGet(),SSI_FRF_MOTO_MODE_0,SSI_MODE,2000000,8);
    	/*SSI使能*/
      SSIEnable(MASTER_SSI_BASE);
     
      /********开始配置DMA*************/
    	/*SSI接收DMA使能*/
    	SSIDMAEnable(MASTER_SSI_BASE,SSI_DMA_RX);
    	/*串口DMA接收配置*/
      uDMAChannelAssign(MASTER_SSI_UDMA_RX_CHANNEL);         	/*DMA通道外设选择*/
    	
    	/*关闭dma通道*/
    	uDMAChannelAttributeDisable(MASTER_SSI_UDMA_RX_CHANNEL,	/*DMA通道*/
                                  UDMA_ATTR_ALTSELECT|       	/*不使用备份控制器*/
    															UDMA_ATTR_USEBURST|					/*brust mode*/
                                  UDMA_ATTR_HIGH_PRIORITY|   	/*不使用高优先级*/
                                  UDMA_ATTR_REQMASK);         /*外设传输请求允许*/
    	
    	
    	 uDMAChannelAttributeEnable(MASTER_SSI_UDMA_RX_CHANNEL, 	/*DMA通道*/
                                 UDMA_ATTR_USEBURST);         /*使用burst请求模式*/
    	
    	/*dma控制器配置 -> 接收*/
    	uDMAChannelControlSet(MASTER_SSI_UDMA_RX_CHANNEL|      	/*DMA通道*/
                            UDMA_PRI_SELECT,                  /*使用主控制器*/
                            UDMA_SIZE_8|                     	/*8bit数据*/
                            UDMA_SRC_INC_NONE|               	/*源地址不递增*/
                            UDMA_DST_INC_8|                  	/*目的地址8字节数据地址递增*/
                            UDMA_ARB_4);                      /*仲裁数目64*/
    
    	/*DMA传输设置 -> 接收*/
      uDMAChannelTransferSet(MASTER_SSI_UDMA_RX_CHANNEL|        	/*DMA通道 */
                             UDMA_PRI_SELECT,                    /*使用主控制器*/
                             UDMA_MODE_BASIC ,                   /*DMA自动模式*/
                             (void *)(MASTER_SSI_BASE+SSI_O_DR), /*源地址*/
                             spi_rx_buf,                  		   /*目的地址*/
                             sizeof(spi_rx_buf));         		   /*传输字节个数*/
    
    	uDMAChannelEnable(MASTER_SSI_UDMA_RX_CHANNEL);           	/*启动DMA接收	*/
     
      /********开始配置DMA*************/
    	/*SSI发送DMA使能*/
    	SSIDMAEnable(MASTER_SSI_BASE,SSI_DMA_TX);
    	/*串口DMA发送配置*/
      uDMAChannelAssign(MASTER_SSI_UDMA_TX_CHANNEL);         	/*DMA通道外设选择*/
    	
    	/*关闭dma通道*/
    	uDMAChannelAttributeDisable(MASTER_SSI_UDMA_TX_CHANNEL,	/*DMA通道*/
                                  UDMA_ATTR_ALTSELECT|       	/*不使用备份控制器*/
    															UDMA_ATTR_USEBURST|					/*brust mode*/
                                  UDMA_ATTR_HIGH_PRIORITY|   	/*不使用高优先级*/
                                  UDMA_ATTR_REQMASK);         /*外设传输请求允许*/
    	
    	
    	 uDMAChannelAttributeEnable(MASTER_SSI_UDMA_TX_CHANNEL, 	/*DMA通道*/
                                 UDMA_ATTR_USEBURST);           /*使用burst请求模式*/
    	
    	/*dma控制器配置 -> 发送*/
    	uDMAChannelControlSet(MASTER_SSI_UDMA_TX_CHANNEL|      	/*DMA通道*/
                            UDMA_PRI_SELECT,                  /*使用主控制器*/
                            UDMA_SIZE_8|                     	/*8bit数据*/
                            UDMA_SRC_INC_8|               	  /*源地址递增*/
                            UDMA_DST_INC_NONE|                /*目的地址不递增*/
                            UDMA_ARB_4);                      /*仲裁数目1*/
    
    	/*DMA传输设置 -> 发送*/
      uDMAChannelTransferSet(MASTER_SSI_UDMA_TX_CHANNEL|     	   /*DMA通道 */
                             UDMA_PRI_SELECT,                    /*使用主控制器*/
                             UDMA_MODE_BASIC ,                   /*DMA自动模式*/
                             spi_tx_buf,                         /*源地址*/
                             (void *)(MASTER_SSI_BASE+SSI_O_DR), /*目的地址*/
                             sizeof(spi_tx_buf));         		   /*传输字节个数*/
    
    	uDMAChannelEnable(MASTER_SSI_UDMA_TX_CHANNEL);          	 /*启动DMA发送*/
      /*lint +e718*/
    }

    Appreciate that you can help to comments why the MISO will miss part of data during transmission. tks again.

  • tem1 = (_Bool)((uDMAChannelIsEnabled(MASTER_SSI_UDMA_RX_CHANNEL))||(uDMAChannelIsEnabled(MASTER_SSI_UDMA_TX_CHANNEL)))
    if((tem1 == (_Bool)false) )
    {
    uDMADisable();
    ……………………

    //The time from detection to execution is 50us

    //flip the C4 voltage level
    }

    Can you try DMAChannelModeGet() to determine if the transfer is complete? Does it make a difference?

    Below is an example to use SSI0. You may have used a different SSI module. 

     if (DMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT) == UDMA_MODE_STOP)

    {

    uDMADisable();
    ……………………

    //The time from detection to execution is 50us

    //flip the C4 voltage level

    }

  • Hi Tsai:

     Cool! tks for the reply.

     For system level ,what s the major difference of the DMAChannelModeGet()  and uDMAChannelIsEnabled()

     As i see, when the transfer is complete,  the DMAChannelModeGet mode is UDMA_MODE_STOP .

     For uDMAChannelIsEnabled() ,it checks to see if a specific uDMA channel is enabled, when the transfer is complete,the channel is automatically disabled, so false status can be checked. 

     So as i see ,they both suitable to detect the DMA status, is there anything i miss?

     tks for your comments.

  • Hi,

      When you use uDMAChannelIsEnabled to determine the status of the channel, it is possible that the channel is disabled before the data is actually transferred completely. For example, let's say you have a total of 100 bytes to transfer and you have 4 bytes remaining to transfer. Since uDMA knows that these 4 bytes are the last 4 bytes, it may have disabled the channel as soon as it starts to transfer these bytes. However, the transfer actually will take some cycles to complete. This may be the reason that you see that the value in  uDMAChannelIsEnabled indicates it has finished but the transfer is still going on. I hope that by using UDMA_MODE_STOP, it actually waits until the transfer is completely done before updating the channel status.