- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello.
I am trying to use my PSOC as a slave device, only it is the one carrying the information I need to transmit (reading from a temperature sensor), so I set my ESP32 as a master and it needs to read the information the PSOC is relaying to me.
I read the datasheet and in the slave operation section there is a write example where it is stated that "You could create an almost identical read buffer example by replacing the write functions and constants with read functions and constants". This does not make a lot of sense to me though as the write is a waiting operation where the slave only needs to wait for the master to complete the action, but the read is something that has to be processed AFTER the request from the master... the if clause from the example itself "waits" for a read to be completed, but only then will I actually write in the rdBuffer the info im trying to send, which doesn't make a lot of sense to me.
I would appreciate some help understanding the read loop or any example that I can get my hands on that is not using EZI2C and not assuming that my master is another PSOC:
Thank you and here is my main code:
void Initialize(void)
{
CyGlobalIntEnable; // Uncomment this line to enable global interrupts.
UART_1_Start();
CyDelay(100);// waiting for clear start after power on
UART_1_PutCRLF(' ');
UART_1_PutString("Temperature sensor Maxim DS18B20:\r\n");
DS18x8_1_Start();
void I2C_SlaveInitReadBuf(uint8 * rdBuf, uint8 bufSize);
void I2C_SlaveInitWriteBuf(uint8 * wrBuf, uint8 bufSize);
I2C_slave_Start();
temp_interrupt_StartEx(isr_Timer);
}
int main()
{
Initialize();
flag_Timer = 1; // force first measument instantly
float temp_read;
int i;
for(;;)
{
temp_read=read_temperature(); // returns a float with the temperature
//cast_array = (uint8*)(&temp_read); //supostamente fica com 4 blocos de 4 bytes para dar os 16 bytes do float
memcpy(tempFloatToArray, &temp_read, sizeof(tempFloatToArray)); //transforms the float into a char array with 4 bytes
/* Wait for I2C master to complete a read? */
if((0u != (I2C_slave_SlaveStatus() & I2C_slave_SSTAT_RD_CMPLT)) && (temp_read != -1000))
{
byteCnt = I2C_slave_SlaveGetReadBufSize(); //number of bytes to read
I2C_slave_SlaveClearReadStatus();
for(i=0; i < byteCnt; i++)
{
rdBuf = tempFloatToArray; /* Data ready to be read */
}
CyDelay(100);
I2C_slave_SlaveClearReadBuf();
}
}
} //main
Solved! Go to Solution.
- Labels:
-
PSoC 5 Device Programming
-
PSoC 5LP
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Pedro,
I see that temp_control variable is used in for loop. Is this the flag_timer.
I assume temp_control variable is '1' only during the first iteration of the for loop and hence, the read buffer is loaded initially before a read transaction is initiated from master.
Initializing the read and write buffers is done by calling the initiReadBuf and initWriteBuf.
To check if a read transaction is completed, you can check if the slave status returned is I2C_SSTAT_RD_CMPLT.
I have attached an example project where the master reads 5 bytes of data from the PSoC 5 LP I2C slave.
You could use this as reference and modify according to your application.
Thanks,
Shanmathi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
The read buffer is initially loaded with the data, the I2C slave (PSoC) has to send to the I2C master (ESP32).
So that, when a read transaction is initiated by the master, the data available in the read buffer is transmitted.
Once a read transaction is completed, the read buffer is again loaded with the temperature data, so that when the next read transaction is initiated by the master, the read buffer has data to be sent to the master.
You could also load data in to the read buffer, whenever read transfer is not in progress, using I2C_SSTAT_RD_BUSY slave status.
You can modify your code in the following way.
if((0u != (I2C_slave_SlaveStatus() & I2C_slave_SSTAT_RD_CMPLT)) && (temp_read != -1000)) //Check if read transaction is completed
{
byteCnt = I2C_slave_SlaveGetReadBufSize(); //number of bytes that was read by the master
I2C_slave_SlaveClearReadStatus();
if (byteCnt == bufSize) // Check if all the bytes in read buffer are read by the master
{
I2C_slave_SlaveClearReadBuf(); // Clear the read buffer to load with the new data
for(i=0; i < byteCnt; i++)
{
rdBuf = tempFloatToArray; /* Data ready to be read */
}
CyDelay(100);
}
}
Thanks and regards,
Shanmathi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the help nsha.
I understand the code if it is at least the second time the master reads something from the slave. However, the very first time the master issues a request to the PSOC my rdBuf is not yet loaded, nor will it go through the conditions above because the master has not read anything yet. Does this mean that whenever I get a temperature value from my sensor I have to load it into the rdBuf so it is ready to be accessed by the master?
This is my issue understanding the algorithm, I just don't get how the master can read a static buffer if I didn't put anything in it, only AFTER verifying if the master has read everything..
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
1. After initialization, you should read the temperature data and load it in to the read buffer. This would ensure that valid temperature data is read by the master during the first read operation
2. Before checking if read is completed, you can load the read buffer with temperature data, when there is no read transaction in progress.
(using I2C_SSTAT_RD_BUSY slave status)
Thanks,
Shanmathi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Shanmathi
I'm still not able to get a proper connection between my master (ESP32) and my slave (PSOC).
I've added a control variable to simply load the information into the buffer the first time it runs and left it as it was, but on my esp32 side I get no wire.available information.
Here is the code, I would really appreciate if you noticed something wrong with my line of thinking
void Initialize(void)
{
CyGlobalIntEnable; // Uncomment this line to enable global interrupts.
UART_1_Start();
CyDelay(100);// waiting for clear start after power on
UART_1_PutCRLF(' ');
UART_1_PutString("Temperature sensor Maxim DS18B20:\r\n");
DS18x8_1_Start();
void I2C_SlaveInitReadBuf(uint8 * rdBuf, uint8 bufSize);
void I2C_SlaveInitWriteBuf(uint8 * wrBuf, uint8 bufSize);
I2C_slave_Start();
temp_interrupt_StartEx(isr_Timer);
}
float read_temperature(){
float temp=0;
int presence=-1;
if(flag_Timer) //read DS18B20 on timer, intervals >1sec
{
flag_Timer = 0;
presence = DS18x8_1_SendTemperatureRequest(); //
}
if (DS18x8_1_DataReady) // DS18 completed temperature measurement - begin read data
{
DS18x8_1_ReadTemperature(); //
ReportTemperature();
temp = DS18x8_1_GetTemperatureAsFloat(1);
return temp;
}
return -1000;
}
int main()
{
Initialize();
char tempFloatToArray[4];
flag_Timer = 1; // force first measument instantly
float temp_read;
int i;
for(;;)
{
temp_read=read_temperature(); // returns a float with the temperature
memcpy(&tempFloatToArray, &temp_read, sizeof(tempFloatToArray)); //transforms the float into a char array with 4 bytes
if (temp_control){
byteCnt=I2C_slave_slRdBufSize;
for(i=0; i < byteCnt; i++)
{
rdBuf[byteCnt-i] = tempFloatToArray; //data readyto be read
}
temp_control=0;
}
if((0u != (I2C_slave_SlaveStatus() & !I2C_slave_SSTAT_RD_BUSY)) && (temp_read != -1000))
{
byteCnt = I2C_slave_SlaveGetReadBufSize(); //number of bytes to read
if(byteCnt == I2C_slave_slRdBufSize){ //check if all the bytes in the rdBuf are read by the master
I2C_slave_SlaveClearReadStatus();
for(i=0; i < byteCnt; i++)
{
rdBuf = tempFloatToArray; //data readyto be read
}
//CyDelay(100);
}
I2C_slave_SlaveClearReadBuf();
}
}
} //main
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Pedro,
I see that temp_control variable is used in for loop. Is this the flag_timer.
I assume temp_control variable is '1' only during the first iteration of the for loop and hence, the read buffer is loaded initially before a read transaction is initiated from master.
Initializing the read and write buffers is done by calling the initiReadBuf and initWriteBuf.
To check if a read transaction is completed, you can check if the slave status returned is I2C_SSTAT_RD_CMPLT.
I have attached an example project where the master reads 5 bytes of data from the PSoC 5 LP I2C slave.
You could use this as reference and modify according to your application.
Thanks,
Shanmathi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Shanmathi
Unfortunatly that's essentially what I did when I tried to redo the code. Yes, temp_control is meant to be used as a one time only variable and the rest of the code will run in loop forever after that first iteration.
I'm still having the same issue. I get a couple of values (albeit some of them are "nan", not sure if that's related) and eventually the master stops having valid returns for the request data function, ie it's as if the PSOC disappeared from the bus.
Any help or debug tool at this point would be really useful if anyone knows of any..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Pedro,
You can check the following protocol analyzers
Beagle I2C/SPI Protocol Analyzer - Total Phase
Logic Analyzers from Saleae - #1 with Professional Engineers
This would help debug further on the issue.
Thanks,
Shanmathi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Shanmathi.
Yesterday I think I managed to understand better why it was failing. By changing the delay time it takes for the loop to complete on the ESP32 side I was able to roughly get it to work continuously. I'm not sure why it would matter for the delay time to be any different, as the transactions are done within I2C's own clock, hence the clk connection.
Will try those tools now to see if I can understand the issue correctly.