asuol / RTEMS_rpi_testing

Test cases and drivers for the Raspberry Pi BSP on RTEMS
3 stars 2 forks source link

SPI device driver #3

Open Zetlark28 opened 3 years ago

Zetlark28 commented 3 years ago

Hi, I'm working with your SPI device driver but for the MCP4822 component, and it's not working. There isn't any compiler or run-time errors, but it seems that the MCP4822 doesn't receive data. This is the edited code of the driver:

`static rtems_libi2c_tfr_mode_t tfr_mode = {
  .baudrate = 20000000,
  .bits_per_char = 8,
  .lsb_first = FALSE,
  .clock_inv = TRUE,
  .clock_phs = FALSE
};

static rtems_status_code spi_mcp4822_write(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *arg
) {
    rtems_status_code sc = RTEMS_SUCCESSFUL;
    rtems_libio_rw_args_t *rwargs = arg;
    int cnt = rwargs -> count;
    unsigned char *buf = (unsigned char *) rwargs -> buffer;
    /*send start*/
    sc = rtems_libi2c_send_start(minor);
    if(sc<0){
        printf("send start error \n");
        fflush(stdout);
        return sc;
    }else{
        printf("start sended \n");
        fflush(stdout);
    }
    /* ioctl*/
    sc = rtems_libi2c_ioctl(minor, RTEMS_LIBI2C_IOCTL_SET_TFRMODE, &tfr_mode);
     if ( sc != RTEMS_SUCCESSFUL ) {
        printf("ioctl error \n");
        fflush(stdout);
        return sc;
     }else{
        printf("ioctl setted \n");
        fflush(stdout);
     }
    /*send addr*/
    sc = rtems_libi2c_send_addr(minor, FALSE);
      if ( sc != RTEMS_SUCCESSFUL ) {
          printf("send address error \n");
      fflush(stdout);
         return sc;
      }else{
         printf("address sended \n");
     fflush(stdout);
    }

    /*write bytes*/
    int data_sent_cnt = rtems_libi2c_write_bytes(minor, buf, cnt);
    if (data_sent_cnt < 0) {
      printf("write bytes error \n");
      fflush(stdout);
          return RTEMS_IO_ERROR;
    }else{
          printf("wrote %d bytes \n", data_sent_cnt);
          fflush(stdout);
    }
    /*send stop*/
    sc = rtems_libi2c_send_stop(minor);
    if ( sc != RTEMS_SUCCESSFUL ) {
      printf("send stop error \n");
      fflush(stdout);
         return sc;
    }else{
    printf("stop sended \n");
    fflush(stdout);
    }
    return RTEMS_SUCCESSFUL;
}

/*read not used, data cannot be read from mcp4822 */
static rtems_status_code spi_mcp4822_read(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *arg
) {
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  return sc;
};
...`

rtems_status_code spi_mcp4822_read is empty because the MCP4822 can't be read.

I read the issue about the I2C device driver, and I understand that the libi2c is deprecated

I'm working with RTEMS v5.1 and I see that they add the SPI framework: https://git.rtems.org/rtems/commit/?h=5&id=a42be52bbf2b3a549d4b9635a5a93215dacd0657. Do you have any advice?

Thank you in advice for your help

asuol commented 3 years ago

Hello Zetlark28,

Few points to consider:

Your application should follow the same SPI bus and device driver initialization and usage flow as in https://github.com/asuol/RTEMS_rpi_testing/blob/master/SPI_bus/Test_cases/SPI_23k256_TEST/init.c

As for the new SPI framework, both API's (libi2c and the linux ported one) are available on RTEMS. The RPI SPI device driver (https://git.rtems.org/rtems/tree/bsps/arm/raspberrypi/spi/spi.c) is developed using the libi2c API, so currently that is the API required for using SPI with the RPI. The libi2c is deprecated in the sense that it should not be used to develop new BSP drivers, but it is still available as older drivers (such as the RPI SPI driver) were not ported yet to the new SPI framework.

Zetlark28 commented 3 years ago

Hi asuol, sorry to bother you again.

I check all points:

It seems that the CE0 pin doesn't switch to level high when the write operation it's finished. I connect the CE0 pin to a LED and it's turned off during the write operation, but it doesn't turn on when it's finished. It's possible that the function rtems_libi2c_send_stop(minor) doesn't work?

Thank you.

asuol commented 3 years ago

The SPI interface supported in the RTEMS SPI driver is the standard 4-wire (or 3-wire if the driver is configured for bidirectional mode) SPI protocol, meaning it should only support full-duplex communication, where to send a byte to the slave device the slave device must send a (possibly dummy) byte back.

However since your device does not send data back, the raspberry may not actually send data to it, hence why I believe you see the CS line still low after the transfer call returned - the data was placed in the TX FIFO but the RPI is waiting for (dummy) data from the slave so it can send your data (full-duplex communication).

I never tested the RTEMS RPI SPI driver with an unidirectional slave device, and I believe the way the RTEMS driver is implemented today does not support this type of slave device.

I realize now that I actually stated in the driver itself that write-only devices were not supported (https://git.rtems.org/rtems/tree/bsps/arm/raspberrypi/spi/spi.c#n19)

Sorry for not making this clearer sooner, it has been a while since I last had a look into this driver.

Zetlark28 commented 3 years ago

Hi asuol, thank you very much for the explanation.

Zetlark28 commented 3 years ago

Hi asuol, sorry I reopened the issue but I have some news and I was wondering if you could help me to understand this behavior. I bought an oscilloscope to see the signal of the pin before I was using a multimeter so I wasn't very accurate.

It's seems that CS0 pin is inverted (yellow = MOSI, CS = cyan) : spi_write_graph

But the VoutA change the value: spi_write_graph2

Do you know if the behaviour of CS can be inverted?

Thank you

asuol commented 3 years ago

You can invert (active high instead of low) the CS line by setting the CSPOL or CSPOL0 field to 1 in the RPI SPI CS register (check the RPI datasheet at https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf page 155). In the RTEMS RPI driver this register is named "BCM2835_SPI_CS"

However the datasheet for your device states that the CS line is to be held low during writes. Also, is the MOSI wave representative of the data you are sending? Are you sending 0xFFFF in the first image?

You should also check the clock line to see if the data transfer on the MOSI line matches the clock pulses, or compare your waveforms with the ones in page 23 of https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf

As for your second diagram, assuming the yellow line is VoutA, it is expected from looking at the write command waveforms in the device datasheet referenced above for the Vout line to be idle during writes (i.e.: when the CS line is low)

Zetlark28 commented 3 years ago

Hi, thank you for the explanation.

I invert the CS line before the write commande like you said:

uint32_t *pSpiCSReg = (uint32_t*) BCM2835_SPI_CS;

*pSpiCSReg |= (1<<6);

But the CS line is low only on the first write command, and then its behavior is inverted. I edit the program to execute the write command 5 times and this is the result: spi_write_graph3 MOSI -yellow, CS - cyan.

I noticed that the MOSI wave shown in the diagram I sent wasn't correct, I fix the bug and now it sends 0x3FFF correctly spi_write_graph4 MOSI - yellow, SCLK - cyan. I compared the waveforms of SCKL and MOSI with the ones in the datasheet and they seem equals.

About the second diagram, I don't know why the VoutA line increase at the last 2 write command: image If I have any news about it I will notice you.

Thank you for your patience and support.

p.s. I'm using the libi2c API and not the framework

asuol commented 3 years ago

When writing values to hardware registers it is best to use the volatile keyword to ensure that the the compiler does not optimize the operation out.

Regarding your ps at the end, are you talking about the new SPI driver framework? Are you developing a separate SPI driver or modifying the existing RPI spi driver (at https://git.rtems.org/rtems/tree/bsps/arm/raspberrypi/spi/spi.c)?

As for the VoutA line increase, what are your commands trying to do? Are all commands 0x3FFF?