PSOC as a slave device - transmitting data to be read by master

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

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

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.

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

View solution in original post

8 Replies
ShanmathiN_06
Employee
Employee
100 replies posted 50 replies posted 25 replies posted

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

0 Likes
Anonymous
Not applicable

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

0 Likes

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

0 Likes
Anonymous
Not applicable

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

0 Likes
lock attach
Attachments are accessible only for community members.

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

Anonymous
Not applicable

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..

0 Likes

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

Anonymous
Not applicable

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.

0 Likes