dga Posted May 30 Share Posted May 30 Hello, I work on a gateway built around an orange PI 2. The orange PI has to manage 3 spi devices (an RTC, a flash and a radio). So I have enabled the spidev module on the orange PI and I use two overlay to get 3 /dev/spidev1.x (x=/dev/spidev1.,1 and2) devices with 3 distinct CS. See my the armbianEnv.txt file: # cat /boot/armbianEnv.txt verbosity=1 logo=disabled console=both disp_mode=1920x1080p60 overlay_prefix=sun8i-h3 overlays=i2c0 pwm spi-spidev usbhost2 usbhost3 rootdev=UUID=64a7c5d3-32a7-4eaf-9e69-a0dd046580ae rootfstype=ext4 param_spidev_spi_bus=1 param_spidev_max_freq=100000000 user_overlays= spi1-triple-spidev-cs sun8i-h3-spi1-add-cs1-cs2 usbstoragequirks=0x2537:0x1066:u,0x2537:0x1068:u See dts file to get 3 spi devices: # cat spi1-triple-spidev-cs.dts /dts-v1/; /plugin/; / { compatible = "allwinner,sun4i-a10", "allwinner,sun7i-a20", "allwinner,sun8i-h3", "allwinner,sun50i-a64", "allwinner,sun50i-h5"; fragment@0 { target = <&spi1>; __overlay__ { #address-cells = <1>; #size-cells = <0>; status = "okay"; spidev@0 { reg = <0>; /* Chip Select 0 */ compatible = "spidev"; spi-max-frequency = <1000000>; status = "okay"; }; spidev@1 { reg = <1>; /* Chip Select 1 */ compatible = "spidev"; spi-max-frequency = <1000000>; status = "okay"; }; spidev@2 { reg = <2>; /* Chip Select 2 */ compatible = "spidev"; spi-max-frequency = <1000000>; status = "okay"; }; }; }; }; See dts file to configure CS for spidev1.1 and spidev1.2 (spidev1.0 has the native CS) # cat sun8i-h3-spi1-add-cs1-cs2.dts /dts-v1/; /plugin/; / { compatible = "allwinner,sun8i-h3"; fragment@0 { target = <&pio>; __overlay__ { spi1_cs1: spi1_cs1 { pins = "PG6"; function = "gpio_out"; output-high; }; }; }; fragment@1 { target = <&pio>; __overlay__ { spi1_cs2: spi1_cs2 { pins = "PA19"; function = "gpio_out"; output-high; }; }; }; fragment@2 { target = <&spi1>; __overlay__ { pinctrl-names = "default", "default", "default"; pinctrl-1 = <&spi1_cs1>; pinctrl-2 = <&spi1_cs2>; cs-gpios = <0>, <&pio 6 6 0>, <&pio 0 19 1>; }; }; }; So the spi driver (in mode 0) works fine for the flash and the RTC, but there is an issue with the radio (on /dev/spidev1.1 with the CS on pin PG6 and active low) because there is a falling edge active before the first rising edge of the clock (see following picture): See what is expected by the spec of the radio: Now I have to find a solution to fix this issue but I not sure to get it rapidly ... But may be some people have ever faced this issue as the radio Nordic 905 is probably not the only one chip touchy to this kind of timings between the CS and the CLK. So any help is welcome ! Best Regards, Damien 0 Quote Link to comment Share on other sites More sharing options...
dga Posted June 3 Author Share Posted June 3 Hello, I have some news to explain the issue ... The spi access done in the previous message is done with the spidev tool : https://github.com/rm-hull/spidev-test/blob/master/spidev_test.c When you launch a command with this tool, the spi mode is always re-configure and so we always get the unexpected clock falling edge leading to command executed with a clock shift for some spi components. However, I have implemented the following type of code to initialize in a first time the file descriptor use to communicate the the spi device, and the use write primitive to perform two write and read access consecutively: // Take care I have just sump up the type of code I use to explain the issue FILE *fd = open("/dev/spidev1.1", O_RDWR); uint8_t mode = SPI_MODE_0; uint8_t bits = 8; uint32_t speed = 500000; unsigned char payload_w1[2] = {0x00, 0x55}; unsigned char payload_r[2] = {0x10, 0x00}; // init file descriptor ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); // spi access write(fd,payload_w1,2); // write 0x55 (issue : in fact 0x54 is written instead of 0x55 due to the the unexpected CLK falling edge) write(fd,payload_r,2); // Read 0x54 payload_w1[1] = 0x77; // change write value write(fd,payload_w1,2); // write 0x77 write(fd,payload_r,2); // read 0x77 exit(0); With the logic analyzer, we can see that the unexpected CLK falling edge is only present during the first spi access with this type of code implementation: Conclusion: It seems that the unexpected CLK falling edge is only present during the first access (when the spi mode is configured). So I have to find the good way to implement the spi driver to avoid this issue that can appear with some SPI components. 0 Quote Link to comment Share on other sites More sharing options...
dga Posted June 7 Author Share Posted June 7 Hello ! I thought to have found a work around by doing a first access to by pass "the unexpected timing", but time to time it does not work ! See code of the work around tested: void spi_transfer(enum Chip chip, unsigned char* txBuffer, size_t len, bool with_rx) { int ret; int fd; uint8_t bits; uint32_t speed; uint8_t mode; unsigned short delay; char * tx = NULL; char * rx = NULL; char hex_dump_tx_prefix[9] = {0}; char hex_dump_rx_prefix[9] = {0}; switch(chip){ case RADIO: fd = st_spi.fd_radio; speed = st_spi.speed_radio; mode = st_spi.mode_radio; bits = st_spi.bits_radio; delay = st_spi.delay_radio; strcpy(hex_dump_tx_prefix,"tx_radio"); strcpy(hex_dump_rx_prefix,"rx_radio"); break; case RTC: fd = st_spi.fd_rtc; speed = st_spi.speed_rtc; mode = st_spi.mode_rtc; bits = st_spi.bits_rtc; delay = st_spi.delay_rtc; strcpy(hex_dump_tx_prefix,"tx___rtc"); strcpy(hex_dump_rx_prefix,"rx___rtc"); break; case FLASH: fd = st_spi.fd_flash; speed = st_spi.speed_flash; mode = st_spi.mode_flash; bits = st_spi.bits_flash; delay = st_spi.delay_flash; strcpy(hex_dump_tx_prefix,"tx_flash"); strcpy(hex_dump_rx_prefix,"rx_flash"); break; default: printf("Unexpected chip value !\n"); exit_with_trace(EXIT_STATUS_SPI_ERROR, ulTraceModule, __FUNCTION__, __FILE__, __LINE__); break; } tx = malloc(len); check_malloc(tx, ulTraceModule, __FILE__, __LINE__); rx = malloc(len); check_malloc(rx, ulTraceModule, __FILE__, __LINE__); memcpy (tx, txBuffer, len); unsigned char payload_wa_radio[2] = {0x20, 0x00}; struct spi_ioc_transfer tr_wa_radio = { .tx_buf = (unsigned long)payload_wa_radio, .rx_buf = (unsigned long)0, .len = 2, .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx, .rx_buf = (unsigned long)rx, .len = len, .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; if (mode & SPI_TX_QUAD) { tr.tx_nbits = 4; } else if (mode & SPI_TX_DUAL) { tr.tx_nbits = 2; } if (mode & SPI_RX_QUAD) { tr.rx_nbits = 4; } else if (mode & SPI_RX_DUAL) { tr.rx_nbits = 2; } if (!(mode & SPI_LOOP)) { if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) { tr.rx_buf = 0; } else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) { tr.tx_buf = 0; } } #if DBG_SPI hex_dump(tx, len, 32, hex_dump_tx_prefix); #endif //toolMutexLock(&MutexSPI); if (chip == RADIO) { // This part of code is a workaround for the radio because the radio spi is touchy to the clock timing of // the first spi access as the mode is set during the first access. // The workaround consists in doing a first access without impact on the radio configuration to bypass the // issue, and then a second access to really execute the spi command. // For the first access, we send command "0x00, 0x20" which is interpreted by the radio "0x00, 0x10" due to the // the clock timing. So we only do a read access at the address 0 of the config register without impact on the radio configuration. // Let's see task #30190 for more details. ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr_wa_radio); if (ret < 1) { printf("can't send spi message\n"); exit_with_trace(EXIT_STATUS_SPI_ERROR, ulTraceModule, __FUNCTION__, __FILE__, __LINE__); } } ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) { printf("can't send spi message\n"); exit_with_trace(EXIT_STATUS_SPI_ERROR, ulTraceModule, __FUNCTION__, __FILE__, __LINE__); } //toolMutexUnlock(&MutexSPI); if (with_rx == true) memcpy (txBuffer, rx, len); #if DBG_SPI hex_dump(rx, len, 32, hex_dump_rx_prefix); #endif free(rx); free(tx); } See capture bellow doing a read access in loop on the radio spi. Time to time, there is also an expected CLK timing on the second access. Conclusion: Doing a first access to bypass the unexpected timing is not enough. I have to add something else or find another solution ... 0 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.