SPI Slave Tx Buffer Problem (PSOC 5)

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
PatrickU
Level 1
Level 1
First reply posted First question asked Welcome!

I am using a PSOC 5 (CY8CKIT-059) as a SPI slave in a project. I am trying put a status byte in the slave SPI tx buffer to serve as the default data read by the master when there is no data to transmit from the slave.  A ready byte when the slave is not processing, a busy byte when it is (or actual data from the slave).
The psoc's rx buffer is handled via dma. When the dma irq triggers for the single command byte, it clears the tx buffer (hardware), and places the busy byte in the tx buffer while it figures out what to do with the command received in the main loop. When it done executing the command, it clears the tx fifo once again and places the ready byte in the tx buffer. The problem I am running into is that at higher spi speeds (200khz in this case), the ready byte does not appear to be placed in the tx fifo. Instead, the busy byte is always returned. At lower speeds, it works as expected. I have included a bare-bones project showing the problem. Single bytes come in from the master at approx a 1 sec interval so there should not be a timing problem replacing the busy byte with the ready byte in the tx buffer. Nevertheless, the response received by the master will change based on the bus speed (at speeds around 190000 and higher, the slave will always respond with busy). Any idea what is going on here?

 

 

 

#define    PSPI_READY      0xAD
#define    PSPI_BUSY       0xAA

static uint8_t _PSPI_DMA_TD = 0x00;
static uint8_t _PSPI_DMA_Channel = 0x00;

volatile uint16 _PSPICMDFlags = 0x00;
volatile uint8_t _PSPICurCMD = 0x00;
uint8_t _PSPIInputBuffer[PSPI_BUF_SIZE] = {0};

volatile static uint32_t _PSPIRecvCnt = 0;

void Init_PSPIDMA(void) {
    
    // we are going to grab 1 byte from the SPI at a time
    _PSPI_DMA_Channel = PSPI_DMA_DmaInitialize(1,1, HI16((uint32)PSPI_RXDATA_PTR), HI16((uint32)(&_PSPIInputBuffer[0])) );
     
    /* Allocate TD - _PSPI_DMA_TD */
    _PSPI_DMA_TD = CyDmaTdAllocate();    
    
    /* Set the source of TD_rx as SPIS_RXDATA_PTR Address and the destination SPI slave Rx Buffer */	
    CyDmaTdSetAddress(_PSPI_DMA_TD, LO16(((uint32)PSPI_RXDATA_PTR)), LO16(((uint32)&_PSPIInputBuffer[0])));  

    // Set _PSPI_DMA_TD as the initial TD associated with _PSPI_DMA_Channdel
    CyDmaChSetInitialTd(_PSPI_DMA_Channel, _PSPI_DMA_TD);    
            
    PSPI_RX_DMA_Done_ISR_Start();
}

// set up DMA to transfer burstCnt bursts of 1 byte from the PSPI rx 
//    our DMA irq will trigger letting us know when the data is available
void Set_PSPICmdDMATransfer(uint16_t burstCnt, uint8_t respByte, uint16_t status) {
    
    // assuming the SPI device will echo the last byte in the tx fifo, we will add a busy
    //   byte so the master will know when we are done processing the last command 
    //     this will happen when we change the tx fifo byte to PSPI_READY

    //PSPI_ClearFIFO();
    PSPI_ClearTxBuffer();
    PSPI_WriteByte(respByte);
 
    _PSPICMDFlags = status;
    CyDmaTdSetConfiguration(_PSPI_DMA_TD, burstCnt, DMA_DISABLE_TD, TD_INC_DST_ADR | PSPI_DMA__TD_TERMOUT_EN);
    CyDmaChEnable(_PSPI_DMA_Channel, 1);     
}

void PSPI_RX_DMA_Done_ISR_Interrupt_InterruptCallback(void) {
   
    _PSPIRecvCnt = 0;
  
    PSPI_ClearTxBuffer();
    PSPI_WriteByte(PSPI_BUSY);
           
    // This DMA interrupt will trigger in three cases
    //  In the first, the DMA transfer of a PSPI command byte has finished
    if (_PSPICMDFlags == PSPI_IDLE) {
        _PSPICMDFlags  = PSPI_CMD_READY;
        _PSPICurCMD = _PSPIInputBuffer[0];
        
        // setting up dma here appears results in the ready byte being in the tx buffer
      // Set_PSPICmdDMATransfer(1, PSPI_READY, PSPI_IDLE);
        
    }
}

void Init_System(void) {  
    
    // turn on the PSPI connection
    PSPI_Start();
    
    // start the irq that handles possible lockups
   // PSPI_SS_IRQ_Start();
    
    // prepare the PSPI DMA for incoming PSPI data
    Init_PSPIDMA();    

    // and set up the dma transfer for the command byte
    Set_PSPICmdDMATransfer(1, PSPI_READY, PSPI_IDLE); 
}


int main() {
    CyGlobalIntEnable; /* Enable global interrupts. */
    Init_System();
    
    //Handle_LCDDemo();
    
    while(true) {
        
       // we received a command byte so figure out what we need to to do
       if (_PSPICMDFlags == PSPI_CMD_READY) {
            //Handle_PSPICommand();
            
            // setting up dma here does not place ready byte into tx buffer
            Set_PSPICmdDMATransfer(1, PSPI_READY, PSPI_IDLE);
        }       
    }
}

 

 

0 Likes
4 Replies