I am trying to access the SPI sensor using the SPIDEV driver, but my code is stuck on IOCTL.
I am running embedded Linux on SAM9X5EK (mounting AT91SAM9G25). The device is connected to SPI0. I included CONFIG_SPI_SPIDEV and CONFIG_SPI_ATMEL in menuconfig and added the correct code to the BSP file:
static struct spi_board_info spidev_board_info[] { { .modalias = "spidev", .max_speed_hz = 1000000, .bus_num = 0, .chips_select = 0, .mode = SPI_MODE_3, }, ... }; spi_register_board_info(spidev_board_info, ARRAY_SIZE(spidev_board_info));
1MHz is the maximum received by the sensor, I tried 500 kHz, but when I boot Linux I get an error (too slow) .. bus_num and .chips_select should fix (I also tried all the other combinations). SPI_MODE_3 I checked the data for it.
I am not getting boot errors, and the devices appear correctly as /dev/spidevX.X. I manage to open the file and get a valid file descriptor. Now I am trying to access the device with the following code (inspired by the examples I found on the Internet).
#define MY_SPIDEV_DELAY_USECS 100 // #define MY_SPIDEV_SPEED_HZ 1000000 #define MY_SPIDEV_BITS_PER_WORD 8 int spidevReadRegister(int fd, unsigned int num_out_bytes, unsigned char *out_buffer, unsigned int num_in_bytes, unsigned char *in_buffer) { struct spi_ioc_transfer mesg[2] = { {0}, }; uint8_t num_tr = 0; int ret; // Write data mesg[0].tx_buf = (unsigned long)out_buffer; mesg[0].rx_buf = (unsigned long)NULL; mesg[0].len = num_out_bytes; // mesg[0].delay_usecs = MY_SPIDEV_DELAY_USECS, // mesg[0].speed_hz = MY_SPIDEV_SPEED_HZ; mesg[0].bits_per_word = MY_SPIDEV_BITS_PER_WORD; mesg[0].cs_change = 0; num_tr++; // Read data mesg[1].tx_buf = (unsigned long)NULL; mesg[1].rx_buf = (unsigned long)in_buffer; mesg[1].len = num_in_bytes; // mesg[1].delay_usecs = MY_SPIDEV_DELAY_USECS, // mesg[1].speed_hz = MY_SPIDEV_SPEED_HZ; mesg[1].bits_per_word = MY_SPIDEV_BITS_PER_WORD; mesg[1].cs_change = 1; num_tr++; // Do the actual transmission if(num_tr > 0) { ret = ioctl(fd, SPI_IOC_MESSAGE(num_tr), mesg); if(ret == -1) { printf("Error: %d\n", errno); return -1; } } return 0; }
Then I use this function:
#define OPTICAL_SENSOR_ADDR "/dev/spidev0.0" ... int fd; fd = open(OPTICAL_SENSOR_ADDR, O_RDWR); if (fd<=0) { printf("Device not found\n"); exit(1); } uint8_t buffer1[1] = {0x3a}; uint8_t buffer2[1] = {0}; spidevReadRegister(fd, 1, buffer1, 1, buffer2);
When I ran it, the code was stuck on IOCTL!
I did this because to read the register on the sensor, I need to send a byte with its address to it, and then return the response without changing the CS (however, when I tried to use write () and read (), during training I received same result stuck on them). I know that specifying .speed_hz causes an ENOPROTOOPT error on Atmel (I checked spidev.c), so I commented on this part.
Why is he stuck? I, although it may be, because the device is created, but in fact it does not "feel" any equipment. Since I was not sure that the hardware SPI0 corresponds to bus_num 0 or 1, I tried both, but still do not have time (by the way, which one?).
UPDATE: I managed to get SPI to work! Half of that. MOSI is sending the correct data, but the CLK does not start ... any idea?