I am working on project that requires a I2C communication between a PSoC 5LP (slave device) and a master micro-controller. The board on which the slave device is running has 16 sensors, that are sampled using external analog muxes and the internal Delta Sigma ADC (16-bit resolution). What I would like to achieve is to place the sampled data in a buffer that can be read from the I2C master device. So far, I have implemented the following setup:
the EOC pin of the ADC is connected to the clock input of a counter (required to change the setup the channel of the external analog muxes)
the EOC pin of the ADC is also connected to the drq pin of a DMA (let's call it DMA_ADC), that transfers 32 bytes (16 sensors * 2 bytes) from the ADC to a buffer in RAM (adcBuffer)
another DMA (called DMA_I2C) has its drq pin connected to the nrq pin of the DMA_ADC. As soon as the DMA_ADC has completed the transfer of the bytes, the data are transferred from the adcBuffer to the i2cBuffer
The current implementation works (I can read data from a I2C master and from the Bridge Control Panel). You can test the attached project with a single analog sensor (I typically use a potentiometer) and see the data from the Bridge Control Panel using the attached file. But I do have some questions regarding my implementation.
My first question is the following one: in order to avoid writing to the i2cBuffer when it is currently being read by a I2C master, I added a Control Register to my project. Whenever a I2C transaction (read/write) is in progress (this is detected from a I2C_EntryCallback), the Control Register does not allow to start the DMA_I2C (thanks to a logic AND with the output of the control register and the nrq pin of the DMA_ADC). Is this a correct implementation? What happens if a I2C transaction starts when the DMA_I2C has already started transferring the data?
The second question is this: I have used several I2C sensors, and most of them provided either a data-ready pin or a status bit in some register that allowed to determine if new data could be read from the sensor. What would be, in your opinion, the best way to implement such a thing on a PSoC-based slave device?
Please find attached my current project implementation for the slave device, and a file that you can use with the Bridge Control Panel to test the project.
It's the first time that I make such use of I2C and DMA, so I apoligize if these are silly questions.
The method you are following might have synchronization issues as you mentioned.
Can you try maintaining two separate buffers instead of maintaining a single I2C read buffer?
The first buffer will store the ADC values populated by DMA and the second one is the actual I2C read buffer. Once the Master's read is complete you can copy the I2C read buffer with buffer that contains ADC values.
Since you are loading the I2C read buffer when there is no traffic on the I2C bus, there will not be any synchronisation issues.
You can disable the DMA_ADC also when you are actually copying the ADC buffer values to the I2C read buffer.
thanks for your reply. In my current design I already have two separate buffers (in the project that I posted they are called adcBuffer and i2cReadBuffer). One buffer, adcBuffer, is filled with ADC sampled data through a DMA. The second buffer, i2cReadBuffer, is the actual I2C buffer that is filled with another DMA. My idea was to continuously update the i2cReadBuffer with data from the adcBuffer, and to avoid that, when a master is reading from the i2cReadBuffer, data from the adcBuffer are copied into the i2cReadBuffer.
What you are suggesting to do is to fill the i2cReadBuffer with data contained in the adcBuffer only after a complete I2C read occurred, is this right? My only concern is that, in this way, the output data rate of the I2C slave device only depends on the I2C master.
I'll try for sure what you suggested me and I'll let you know.