OTA preventing GPIO triggering exit from Hibernate

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

cross mob
lock attach
Attachments are accessible only for community members.
MikeAustin
Level 4
Level 4
25 replies posted 25 sign-ins 10 replies posted

I have a simple project that puts my MCU into Hibernate mode, and then when I get a rising edge trigger on a specific GPIO, the MCU comes out of Hibernate mode.  I have an ISR to process the interrupt generated from the GPIO, and am just sending out some debug message via the UART to check that things are functioning as expected.  Seems to work fine in testing.  Attached is the Project for this code (Hibernate_Triger_Test)

When I convert this to a Fixed Stack OTA Bootloadable version, this functionality is lost.  It seems to trigger the hardware out of Hibernate mode, then starts up the Bootloader code, but it isn't servicing my ISR (I check this in my main loop by checking the status of "triggerMode"). Also attached is the Workspace for the OTA version (OTA_Hibernate).

The code snippet is part of a bigger project I'm working on, where I have multiple GPIO's triggering the MCU of out Hibernate, and I rely on the ISR and a check of the Port Register to determine which pin caused the trigger, so without the ISR running, I can't ascertain this.

Can anyone shed light on why the ISR isn't operating when I convert to an OTA version of my code?

Thanks and regards,

Mike

P.S.  I've not included all the code that enables my Bootloadable project to check for an OTA trigger at this point, but ultimately it will be done by writing to a Custom Characteristic, and I've got all the code and done all the testing on that to confirm it works.  Just trying to resolve the ISR issue first.

0 Likes
1 Solution
MikeAustin
Level 4
Level 4
25 replies posted 25 sign-ins 10 replies posted

OK, got this working myself in the end.  Key points for anyone else fumbling through this issue:

1.  On reset (so, exiting Hibernate) the Bootloader code does indeed get run first.  The last step in this is to make a call to Bootloader_Start(), which eventually makes a call to CySoftwareReset().  This last function call clears out all the Port Status registers 😞

2.  To fix this, you have to grab the contents of the relevant Port Status Registers before Bootloader_Start() is called, and then store these somewhere that the Bootloadable code can see. 

To grab the Port Status Register, you just need to read the value of the relevant CYREG_GPIO_PRTx_INTR register (x = relevant port number).  I have all my pins defined in my Bootloadable code, so can't use the PSOC Creator defined names in the Bootloader code.  There may be a way to do this, but it was just easier for me to look at what port I'm using in the Bootloadable code, and make "x" equal that number

To share a variable between Bootloader and Bootloadable code, this post shows a clever way (easier than using SFlash): https://community.cypress.com/t5/PSoC-4-MCU/Help-passing-variable-from-bootloader-to-bootloadable-ap...

Now, the process is:

1.  GPIO triggers MCU out of Hibernate, and this runs Bootloader code

2.  Read value of CYREG_GPIO_PRTx_INTR register and store this in my shared variable (I just needed a uint8)

3.  Allow the Bootloader code to complete its start up, and then it will flick control over to the Bootloadable code (assuming this is valid)

4.  Read the status of the shared variable and then take action based on what that value is.

Cheers,

Mike

View solution in original post

0 Likes
5 Replies
MikeAustin
Level 4
Level 4
25 replies posted 25 sign-ins 10 replies posted

I have a suspicion that its something to do with how the MCU goes through a reset when there is a Bootloader present.  I don't fully understand the whole process, so maybe someone that does can shed some light on it, but it looks to me like whenever my MCU comes out of Hibernate, it runs the Bootloader code to begin with.  The Bootloader then checks that the Bootloadable code is valid, and if it is, switches over to that.

I'm guessing, but have not been able to confirm, that in that process, the status of the relevant Port Register is lost in the transition from Bootloader to Bootloadable, and I probably need to be checking to see which pin caused the exit from Hibernate mode inside my Bootloader code, then somehow passing this information (I've got no idea how I'd go about doing this!) to my Bootloadable code, which can then process this and act on it accordingly.

Would be good if someone that knows more about how all this works could step in and give me a bit of guidance.

Thanks and regards,

Mike

0 Likes
VenkataD_41
Moderator
Moderator
Moderator
750 replies posted 500 replies posted 250 solutions authored

Hi Mike,

In PSoC 4 device family, the Hibernate wake-up is through reset. Please go through point number 3 at the bottom in page number 2 of the following application note:

https://www.cypress.com/file/121271/download

Please note that SRAM will be retained. Please refer secton 3.3.1 in page number 4 of the same application note. 

So, the behavior you are observing in case of OTA is expected phenomena only i.e. after reset the device goes through Bootloader and from there it reaches to Bootloadable. In case of non OTA project the same thing should happen. We will investigate this if this is not happening accordingly.

Thanks

Ganesh

0 Likes
MikeAustin
Level 4
Level 4
25 replies posted 25 sign-ins 10 replies posted

Hi Ganesh,

Yep, I had read all of that application note, so understand how things work under "normal" conditions (i.e. when I don't have a Bootloader present).

I can get my code to work without the Bootloader (non OTA).  That is:

  1. MCU in Hibernate
  2. Trigger on one of the relevant GPIO will bring it out of Hibernate and resets the MCU
  3. This then runs my code, included within which is a call to CySysPmGetResetReason() to see if its a GPIO triggered reset, or a hard reset (e.g. normal power on reset)
  4. If its a GPIO reset, I have an ISR that services the interrupt and sets the value of a variable to whatever the Port Interrupt Status Register is.
  5. I then check which bit in the Port Interrupt Status Register has been set, and I can then process this accordingly and run some code depending upon which GPIO caused the trigger
  6. I then put my MCU back into Hibernate

The issue comes when I include OTA functionality.  When I do this, my ISR is not being triggered.  So, its almost like the Bootloader code, once it has finished doing whatever it does after an MCU reset, clears the status of the Interrupt Registers for both my port, and my ISR, preventing my ISR from ever running once the Bootloadable code gets fired up.

As my pins are all defined in the Bootloadable code, I am not sure how to check the status of the Port Interrupt Status register within the Bootloader code, and then pass this information across to the Bootloadable code (i.e. do I need to store the register value in Flash, or can I somehow have a variable in RAM that both the Bootloader and Bootloadable code can access?)

Cheers,

Mike

0 Likes
MikeAustin
Level 4
Level 4
25 replies posted 25 sign-ins 10 replies posted

OK, got this working myself in the end.  Key points for anyone else fumbling through this issue:

1.  On reset (so, exiting Hibernate) the Bootloader code does indeed get run first.  The last step in this is to make a call to Bootloader_Start(), which eventually makes a call to CySoftwareReset().  This last function call clears out all the Port Status registers 😞

2.  To fix this, you have to grab the contents of the relevant Port Status Registers before Bootloader_Start() is called, and then store these somewhere that the Bootloadable code can see. 

To grab the Port Status Register, you just need to read the value of the relevant CYREG_GPIO_PRTx_INTR register (x = relevant port number).  I have all my pins defined in my Bootloadable code, so can't use the PSOC Creator defined names in the Bootloader code.  There may be a way to do this, but it was just easier for me to look at what port I'm using in the Bootloadable code, and make "x" equal that number

To share a variable between Bootloader and Bootloadable code, this post shows a clever way (easier than using SFlash): https://community.cypress.com/t5/PSoC-4-MCU/Help-passing-variable-from-bootloader-to-bootloadable-ap...

Now, the process is:

1.  GPIO triggers MCU out of Hibernate, and this runs Bootloader code

2.  Read value of CYREG_GPIO_PRTx_INTR register and store this in my shared variable (I just needed a uint8)

3.  Allow the Bootloader code to complete its start up, and then it will flick control over to the Bootloadable code (assuming this is valid)

4.  Read the status of the shared variable and then take action based on what that value is.

Cheers,

Mike

0 Likes
VenkataD_41
Moderator
Moderator
Moderator
750 replies posted 500 replies posted 250 solutions authored

Hello Mike,

Thank you for sharing the solution. There are few other methods which are used to share the data from Bootloader to Bootloadable.

1. You can use checksum exclude region in the Flash to store the data. Please go through the following KBA in which the Capsense data of the Bootloader project is stored in Checksum exclude section and it is being retrieved from Bootloadable project.

https://community.cypress.com/t5/Knowledge-Base-Articles/One-time-IDAC-Auto-Calibration-in-PSoC-4-KB...

2. You can also use User SFLASH region to store the data. The data stored in user SFLASH region will not be erased even after programming. Please refer psoc 4 system reference guide from PSoC Creator Help --> System reference guides --> PSoC 4 System reference guide and refer CySysSFlashWriteUserRow() API to write into user SFLASH. Note that there is no direct API to read from the user SFLASH directly. You need to read directly from the memory. Please refer PSoC 4 programming specifications appnote from the web to get the user SFLASH addresses.

Hope this helps !

Thanks and regards
Ganesh

0 Likes