Is there a way to increase i2c read in linux - c

I have an LSM6DS3 motion sensor connected to the i2c bus of a Qualcomm processor running Linux OS. I have been trying to read the FIFO buffer of the sensor every 20s. It takes around 2 to 3 seconds to read all the data from the sensor FIFO buffer(The FIFO buffer of the sensor is exposed through LSM6DS3_FIFO_DATA_OUT_L and LSM6DS3_FIFO_DATA_OUT_H registers in the sensor).Im using i2c_smbus_read_word_data(int file, __u8 command) APIs to read.In order to reduce this time delay I have set my i2c master clock to 400KHz and tried IOCTLs instead of above APIs but none of the workaround worked.The same sensor I connected to Arduino and tried the same read operation. It took only 1.4s to read the data.Is there any way to increase the i2c read speed in Linux?.

Related

Implementing an SSI slave interface on STM32 Board

I am trying to implement a SSI Slave Protocol on a STM32 Board. Since the STM32 Boards don't have a SSI interface, I used its SPI interface in Slave(Transmit only mode). The master SSI sends 24 clock signals and the slave reacts by sending its data(3 Bytes) over the MISO pins. The problem I am facing is that the data is always shifted on the left on every clock signal coming from the master. For example assuming I am constantly sending 0x010101 from slave.
At first transmission the master receives 0x010101
At Second transmission the master receives 0x020202
At third transmission the master receives 0x040404
Can someone please give me some hints on how to solve this problem?
The data-shift with each transmission can happen when the SPI slave recognizes an (unexpected) additional clock pulse. Looking at the SSI protocol description on Wikipedia this actually makes sense:
In order to transmit N bits of data the master emits N clock cycles, followed by another clock pulse to signal the end of the transfer (so-called "Monoflop Time" - referring to the original hardware implementation of the SSI interface). Since the SPI protocol / SPI slave does not know about this additional clock pulse, it begins to output the first bit of the next data byte, which is in turn not recognized by the SSI master. As a result this leads to a shift in the data bits recognized by the SSI master on the next SSI frame.
Unfortunately, it is not easy to handle the Monoflop time correctly with the SPI slave. In order to deal with the additional clock pulse, we could try to set the SPI frame size to 25 bits on the slave side. Since the STM32 hardware only supports SPI frame sizes between 4 bit and 16 bit, the only choice is to set it to 5 bit. This is not very convenient, since we need to convert the 3 byte (24 bit) output data into 5 blocks of 5 bit (24 bit output data + 1 bit dummy data), but it should work for a "normal" transfer.
Things get more complicated though, if we also want to handle the cases "Multiple transmissions" and "Interrupting transmission" correctly. We need to monitor the clock signal to be able to detect the monoflop timeout. This can be done using a STM32 hardware timer with an external trigger. When the timer expires, we need to reset the SPI unit (in order to handle an interrupted transmission) and update the output value. This "simple" task can be quite challenging since it requires a couple of instructions - requiring a fast MCU depending on the SSI clock frequency.
Alternatively the SSI protocol can be implemented using a software-only "bit banging" solution. But this requires a fast MCU as well in order to handle a fast SSI clock correctly.
IMHO the best solution is to use a small (inexpensive) FPGA to implement the SSI slave and let the MCU feed it with data over a traditional SPI interface.

Issues setting up DMA doublebuffer mode to work with SPI rx only on STM32

I'm attempting to create a data logger that intakes data from a sensor node with three modalities and transmits that data using three different SPI busses to a Nucleo-f746zg. I would then like to use DMA peripheral to memory mode to take the incoming data from each bus and put it into one of three buffers that will eventually get written to a USB flash drive using FATFS. I'm having issues initializing the DMA in double buffer mode. When I look at each register it seems to be configured correctly but none of the interrupts fire and the data transfer doesn't occur.
I know that the SPI data is coming in. I initially tried this using interrupts but the data rate was too fast and I was losing data so I pivoted to DMA. The Data, once it's in the register correctly writes to the USB drive as well. I'm using the "LL" drivers for both SPI and DMA.
This is my current DMA initialization code:
uint16_t TEST_BUFFER_0[10000];
uint16_t TEST_BUFFER_1[10000];
LL_DMA_SetChannelSelection(DMA1,LL_DMA_STREAM_3, LL_DMA_CHANNEL_0);
LL_DMA_SetDataTransferDirection(DMA1,LL_DMA_STREAM_3, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_EnableDoubleBufferMode(DMA1,LL_DMA_STREAM_3);
LL_DMA_SetPeriphIncMode(DMA1,LL_DMA_STREAM_3, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1,LL_DMA_STREAM_3, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1,LL_DMA_STREAM_3, LL_DMA_PDATAALIGN_HALFWORD);
LL_DMA_SetMemorySize(DMA1,LL_DMA_STREAM_3, LL_DMA_MDATAALIGN_HALFWORD);
LL_DMA_DisableFifoMode(DMA1,LL_DMA_STREAM_3);
LL_DMA_SetMemoryAddress(DMA1,LL_DMA_STREAM_3,TEST_BUFFER_1);
LL_DMA_SetMemory1Address(DMA1,LL_DMA_STREAM_3, TEST_BUFFER_0);
LL_DMA_SetDataLength(DMA1,LL_DMA_STREAM_3, 10000);
LL_DMA_SetPeriphAddress(DMA1,LL_DMA_STREAM_3, LL_SPI_DMA_GetRegAddr(SPI2));
LL_DMA_EnableIT_HT(DMA1,LL_DMA_STREAM_3);
LL_DMA_EnableIT_TC(DMA1,LL_DMA_STREAM_3);
LL_DMA_EnableStream(DMA1,LL_DMA_STREAM_3);
LL_SPI_EnableDMAReq_RX(SPI2);
LL_SPI_Enable(SPI2);
I'm not seeing either of the interrupts firing nor am I seeing my buffers get full. I'm not one hundred percent sure what actually initiates the DMA transfer other than the documentation alluding to this occurring automatically when data comes in. I'm kind of stuck at this point and I'm not sure what else to try.

FTDI I2C libMPSSE

I'm working on reading flow rates from a sensrion lg16 flow rate sensor using a USB FTDI I2C dongle. I have all the wiring done and I am able to write to it and verify I am able to write to it correctly using an oscilloscope with an I2C analyzer. My problem is when i try to do a read from the sensor, even when reading to a register after writing to it i dont get missing Acks on the I2C bus.
here my code to read the register i want to see at the moment
bytesToTransfer=0;
bytesTransfered=0;
buffer[bytesToTransfer++]=0xE5;
//buffer[bytesToTransfer++]= 0x7f;
status = I2C_DeviceWrite(ftHandle, slaveAddress, bytesToTransfer, buffer, \
&bytesTransfered, I2C_TRANSFER_OPTIONS_START_BIT|I2C_TRANSFER_OPTIONS_STOP_BIT | I2C_TRANSFER_OPTIONS_FAST_TRANSFER_BYTES);
printf("bytestxd=%d\n",bytesTransfered);
printf("status=%d\n",status);
APP_CHECK_STATUS(status);

Troubleshooting Missing Data Sample Packets in xBee?

I have my first two nodes setup, I have a ZigBee Coordinator API module and a ZigBee End Device API module. I have the end point connected on Analog pins 1-3 with sensors for temp, moisture, and light.
I have the pins D1-3 configured for ADC, and the IR sample rate setting at EA60 for once per 60 seconds.
The frames log on the co-ordinator shows a stream of Explicit RX Indicator frames and Transmit Status frames, but I am seeing no IO Data Sample RX Indicator frames.
Also, I wired an LED to the sleep indicator pin, and it is almost constantly lit, it's certainly not sleeping for a minute at a time.
Any help would be greatly appreciated.
Do the Explicit RX Indicator frames look like they might contain your I/O samples? You might need to set ATAO=0 to receive the 0x92 frame type, but you're probably better off sticking with parsing the Explicit Rx to find the I/O sample payload and using that.
Regarding your sleeping end device, have you configured the various XBee registers to have it sleep? Find the section on sleep in your XBee documentation and read through it entirely -- there are many configuration options. For the ZigBee specification, you'll need to wake up every 7 seconds, even if it's just a short wakeup for the device to ping its parent device and check for network messages.
Finally, make sure you've wired your LED correctly. If the sleep indicator pin is active low, it will be pulled low whenever sleeping. And the end device will be waking for a short amount of time, possibly too short to see on an LED. You could use a scope or a logic analyzer to monitor the pin for changes instead.

how to access to trasfer data form io to memory on ARM9 s3c2440 with DMA or without DMA

I want to transfer 8 bit parallel data from IO to memory ,the data is coming very fast at speed of roughly 5 Mhz ,I am using embedded linux on ARM9 based kit by friendly arm which is using S3C2440(400Mhz) processor can any body pleas tell me where to start,my data is a video signal that is coming from a adc
I have read the on internet that I can do this using DMA but I need a start ...
Forget about DMA on this device. The ADC is not available as a DMA source. One reason for this is that DMA is only useful for transferring multiple bytes/words/whatever - the overhead of setting up, starting the DMA and handling an OnCompletion interrupt makes it pointless for occasional transfers of one item. Your ADC has no buffering, just the one output register with 10 sig. bits.
Use an FIQ handler to extract the ADC result. How you buffer the output and signal it for further processing is up to you and the linux driver framework.
have a look at these articles to for brieif theroy
http://my.opera.com/richasn/blog/2011/01/15/application-of-dma-way-in-data-acquisition-in-arm-system
http://my.opera.com/richasn/blog/2011/01/14/application-of-dma-way-in-data-acquisition-in-arm-system

Resources