I have recently implemented communication between Rpi and PSoC5lp (CY8CKIT-059) using 400kHz I2C.
On the PSoC5lp side, I am using a delta sigma ADC buffer (16 bit resolution, 2000 samples/second conversion rate)
I have connected an end of conversion isr to the ADC which checks if a circular buffer is full and if not puts the latest ADC value into a circular buffer (64 samples).
In the main I check if the circular buffer is empty and if not I pull the 16 bit ADC value from the circular buffer, do some bit shifting and store the 2 bytes into the I2C slave read buffer.
On the Rpi master side, I am using the SMBus2 module to read 2 bytes of data at a time from the PSoC5lp slave, appending the data into a tuple and every 5000 samples write the data to a csv file.
The communication appears to work fine, as in I am receiving data of the correct values and able to store this to a csv file. The problem I have is that the sample rate is not correct, I thought continuously pushing the ADC values into a circular buffer and then updating the I2C slave buffer with values pulled from this would maintain the 2000 samples/second conversion rate of the ADC, however when I only have one slave connected - it samples much faster than expected (basically I have an EMG preamplifer connected to the ADC and by crude method I am contracting my muscle for 5 seconds and then dividing the number of samples in the contraction by 5 to get the sample rate). The data looks correct (like a normal muscle contraction) however there are many duplicate consecutive values (e.g. it changes like 5,5,5,5,4,4,4,4,3,3,3,2,2,4,4,4,4) which I don't should happen. I believe that the I2C master might be coming back to the slave before the read buffer has been updated? I am using the EZI2C component at the moment and have followed the routines showed in code examples.
Any help would be much appreciated!
I have attached my project as a compressed folder.
PSoC5 LP MCU
I have analysed your attached project and the following are my suggestions you can try to debug:
1) Can you please confirm if the data in the circular buffer (ADC sample data) is sampled correctly?
2) Try connecting the EzI2C slave to Bridge Control Panel (BCP) using a KitProg or a MiniProg device. This helps in isolating the issue to the PSoC. If the data is received correctly in BCP then the issue is with the RPi implementation.
Please, let us know if further clarification is required.
Thanks for your suggestions Raj,
I believe the ADC data is sampling correctly in the circular buffer because the signals look correct upon visual observation. However perhaps I need to further check the logic of the circular buffer I've implemented. Do you have any suggestions for checking whether the ADC and circular buffer are working correctly?
I will try connecting the psoc to the bridge control panel. Thank you for your suggestions.
One more question I have, with the way ezi2c slave component works, is it only visible to the master again once the slave buffer has been updated? Or does the buffer stay visible to the master all the time, because if the latter I feel that the same slave buffer might be being read multiple times before it's updated. If so is there anyway to hide the buffer from the master until the slave buffer has been updated again?
Hi Raj, I just connected the PSoC5lp to my laptop and used the bridge control panel I2C interface. The I2C bus speed is set to 400 KHz, however the BCP says it is only reading at 313 samples/second (see screenshot). This rate should be a lot higher at 400 KHz? Is the speed of the BCP limited?
The data looks correct and those no duplicates, however I believe this is probably due to the reduction in sample rate. I held a muscle contraction for 3 seconds and as you can see, it is only recording approx. 580 samples (580/3 = 193 samples/second) when it should be the 2000. An I2C clock of 400 KHz should easily be able to achieve a sample rate of 2000?
I don't see the Circular Buffer initialized to 0xFFFF.
Initialization of HEAD and TAIL is done too late. It should be placed ahead of enabling interrupts and certainly ahead of enabling the ADC ISR.
In for() loop of main, it checks for buffer empty:
Shouldn't this be:
if(Is_BufferEmpty() !=0) ( I could be wrong. I lost track of why you're stuffing 0xFFFF into ring buffer).
Is_BufferEmpty() is called while interrupts are enabled. Head and Tail may change before the "if" conditional test is fully executed (if an interrupt occurs during the "if"). You'd need to disable/enable interrupts around this.
You might find this thread useful. It's for PSoC4 (discussion doesn't use EZI2C), but applicable to PSoC5LP too.
Just my $0.02 worth.
ps: I could be totally mis-interpreting how your ring buffer implementation works.
Thank you very much for your response.
Thank you for your advice with the ring buffer - I had not implemented one before so it is great to receive feedback on it. I will implement the changes you suggested with the component initializations/enablings and run again.
Regarding the is_BufferEmpty() function, I believe the logic in the function returns a "-1" if the buffer is empty and a "0" if the buffer is not empty, and I only want to update the I2C slave buffer with the value in the circular buffer if it is not empty, however I could be mistaken. Sorry about the 0xFFFF's, I should have taken those out before submitting to the forum as they would be a little confusing. In some stage of my debugging I decided to place a 0xFFFF in location of the circular buffer which had just been read, thus if the buffer is completely empty then it should just be filled with 0xFFFF's, it was just a quick way for me to check - but I might take this out now.
Thanks for your advice on also making the Is_BufferEmpty() check atomic too, I will move the interrupt disable and enabling to the correct locations. Also thanks for sharing that forum, I think the example code will really help me!
Thanks again for your great advice! I will check back in within a few days and update you on how my testing has gone. 🙂
Thanks again for your suggestions.
I implemented the changes with the circular buffer and also tried tried the interrupt callback method.
However - I still receive consecutive duplicates of ADC data on the raspberry pi. I'm wondering if there is a way to hide the I2C slave buffer from the Rpi master until the slave buffer has been updated? I think this is probably what is causing the issue.