SPI Transmission with additional D/C pin. Timing problems

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

cross mob
user_4611381
Employee
Employee
First like received First reply posted First question asked

Hi,

I'm working on a driver to control a waveshare epaper-display with a PSoC 4200M. For that I am using the CY8CKIT-043. I already found a complete driver library for STM32 and want to port that to PSoC. 

The Driver uses a SPI interface with an additional GPIO pin (the D/C-pin) to give the display a signal if the transmitted data is to be handled as a command (D/C low) or as data (D/C high).

 

In the original driver code (for STM32) this was done by simply write the pin right before the SPI transmission:

 

 

void EPD_SendCommand(EPD* epd, unsigned char command) {
  EPD_DigitalWrite(epd, epd->dc_pin, LOW);
  EpdSpiTransferCallback(command);
}

void EPD_SendData(EPD* epd, unsigned char data) {
  EPD_DigitalWrite(epd, epd->dc_pin, HIGH);
  EpdSpiTransferCallback(data);
}

void EpdSpiTransferCallback(unsigned char data) {
  HAL_GPIO_WritePin((GPIO_TypeDef*)pins[CS_PIN].port, pins[CS_PIN].pin, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi1, &data, 1, 1000);
  HAL_GPIO_WritePin((GPIO_TypeDef*)pins[CS_PIN].port, pins[CS_PIN].pin, GPIO_PIN_SET);
}

 

 

As you can see, there is no control at all if the data has been sent on the bus or not. 

 

If I implement this code on the PSoC 4 using the SCB SPI communication the signals on the bus are a complete mess. While SPI is transferring correctly, the D/C pin changes on and off regardless any timing on the bus.

 

 

void EPD_SendCommand(unsigned char command) {
  EPD_DigitalWrite(PIN_DC, LOW);
  EpdSpiTransferCallback(command);
}

void EPD_SendData(unsigned char data) {
  EPD_DigitalWrite(PIN_DC, HIGH);
  EpdSpiTransferCallback(data);
}
void EpdSpiSelect(){
    SPI_SpiSetActiveSlaveSelect(SPI_SPI_SLAVE_SELECT0); //sets active slave. this slave is then pulled to 0 when transmission starts? SCB datasheet page 110
  } 

void EpdDigitalWriteCallback(uint8_t pin_num, uint8_t value) {
  if (value == HIGH) {
    switch(pin_num){
        case PIN_DC:  CyPins_SetPin(EPD_DC_0); break;
    }
  } else {
    switch(pin_num){
        case PIN_DC:  CyPins_ClearPin(EPD_DC_0); break;
    }  }
}

 

 

 
Therefore, I tried to implement some kind of control if the previous byte has already been sent on the bus:

 

 

void EPD_SendCommand(unsigned char command) {
    while(SPI_SpiIsBusBusy()){
        CyDelayUs(1);
    }  //wait until bus is free 
  EPD_DigitalWrite(PIN_DC, LOW);
  EpdSpiTransferCallback(command);
}

void EPD_SendData(unsigned char data) {
    while(SPI_SpiIsBusBusy()){
        CyDelayUs(1);
    }  //wait until bus is free 
  EPD_DigitalWrite(PIN_DC, HIGH);
  EpdSpiTransferCallback(data);
}

 

 

 Now, the timing of the D/C signal is clearly correlated to the data packets transferred on the bus. However it seems as the D/C signal switches on or off exactly one SPI cycle before it is intended.

In the following logic analyzer snip you can see the issue. The D/C pin should look like the signal drawn in red, but it is early by one SPI cycle.

Unbenannt.png

I have tried for several days now to fix that problem. Does anyone have an Idea on what I could try to get the timings of the signals right?

 

Thank you and best regards

Simon

 

 

 

Appendix: Here you can see the two callback functions I use to switch the D/C pin and transmit the SPI data:

 

 

void EpdSpiTransferCallback(unsigned char data) {
   SPI_SpiSetActiveSlaveSelect(SPI_SPI_SLAVE_SELECT0); 
   SPI_SpiUartWriteTxData(data);
}

void EpdDigitalWriteCallback(uint8_t pin_num, uint8_t value) {
  if (value == HIGH) {
    switch(pin_num){
        case PIN_DC:  CyPins_SetPin(EPD_DC_0); break;
    }
  } else {
    switch(pin_num){
        case PIN_DC:  CyPins_ClearPin(EPD_DC_0); break;
    }  }
}

 

 

 

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
HiOm_1802421
Level 5
Level 5
Distributor - Marubun (Japan)
50 replies posted 50 questions asked 25 replies posted

Hi,

I experimented with SCB_SPI using CY8CKIT-044 (PSoC4200M).

The experimental results are as follows.

The communication interval of my waveform is longer than your result, but it seems to work as expected.

Please refer to the attached project.

HiOm_1802421_1-1612517255321.png

 

View solution in original post

2 Replies
lock attach
Attachments are accessible only for community members.
HiOm_1802421
Level 5
Level 5
Distributor - Marubun (Japan)
50 replies posted 50 questions asked 25 replies posted

Hi,

I experimented with SCB_SPI using CY8CKIT-044 (PSoC4200M).

The experimental results are as follows.

The communication interval of my waveform is longer than your result, but it seems to work as expected.

Please refer to the attached project.

HiOm_1802421_1-1612517255321.png

 

user_4611381
Employee
Employee
First like received First reply posted First question asked

Hi,
Awesome, that works perfectly 🙂

Yes, the communication is slightly longer now, but it only makes a difference of less than 10% of total transmission time (250us per 10 data packets vs. 230us beforehand).
Thank you very much for that fast and very simple solution. To be honest, I thought that using the SCB_SpiIsBusy() function does exactly the same as the SPI_done interrupt. Obviously, that is not the case...

Thanks again and best regards

Simon