Hi everyone,
Recently I have a project to use a Linux host to communicate with an ADC device(SPI communication). I use my knowledge to write a device driver for it.
The goal of this driver is to read ADC data and transfer them to userspace. My idea is when the Linux host gets the DRDY signal(data ready signal, the signal means the data of ADC can be read) from ADC, an interrupt will be triggered, and the SPI read API of the driver will read data from the SPI bus. the data will fill into a buffer, when the buffer is full, the driver sends a SIGNAL to the userspace program, and the data in the buffer will be read by the userspace.
Although this idea may not be a perfect plan to realize my goal, I finish the code above. Unfortunately, I face a question that makes my goal failed.
The SPI transfer API of the Linux host should be put into the bottom half of the interrupt(due to the sleep mechanic of SPI API), that is to say, if the sample rate of AD is too fast, the bottom half of the interrupt may read a delayed data of ADC, when I use 4kHz sample rate, there are 7997 interrupts, but only 7907 data has been read. When I use the 250Hz sample rate, my idea is OK. But, I must use at least 4ksps.
I do not know whether you have some experience with this kind of problem, or maybe my idea is not suited for the high-speed ADC, I hope you can give me some suggestions, thanks a lot.
Here is some core function of my code:
SPI transfer related:
Code:
int get_ad_data(struct spi_device *ad_spi_dev)
{
int ret = -1;
gpio_set_value(ADS1299_CS_PIN, 0);
if( ad_spi_dev )
{
struct spi_transfer tr =
{
.tx_buf = &send_data,
.rx_buf = &get_data,
.len = 27,
};
ret = spi_sync_transfer(ad_spi_dev, &tr, 1);
}
printk("%02x, %02x, %02x\r\n",get_data[6],get_data[7],get_data[8]);
gpio_set_value(ADS1299_CS_PIN, 1);
return ret;
}
Interrupt related:
Code:
static irqreturn_t drdy_handler(int irq, void *dev_id)
{
struct ads1299_dev *dev = dev_id;
schedule_work(&dev->drdy_irq.work_drdy);
return IRQ_HANDLED;
}
static void drdy_work(struct work_struct *work)
{
int ret;
ret = get_ad_data(ads1299_spi_dev);
if (!ret)
{
printk("get data succ\r\n");
}
}