Hardfault when calling GUI_Clear, thread related ?

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Hardfault when calling GUI_Clear, thread related ?

      Hi,

      Based on the discussion in Direct framebuffer access, I started using memdevs.
      But now I run into an exception during when calling GUI_Clear() when the memdev is active (though it might not be memdev related, so i created new topic).

      Background:
      I am using stemwin in a freertos multitasking environment.
      The memory I give to emwin (and in which the memory buffer is located) is located in external SRAM.

      IAR linker file:
      place in ExtSRam_region { block HEAP, section EXT_MEMORY_IF_AVAILABLE };

      GUI_conf.c:

      Source Code

      1. #define GUI_NUMBYTES (1024) * 64
      2. static U32 extMem[GUI_NUMBYTES / 4] @ "EXT_MEMORY_IF_AVAILABLE";
      3. void GUI_X_Config(void)
      4. {
      5. GUI_ALLOC_AssignMemory(extMem, GUI_NUMBYTES);
      6. }
      The calls I do are

      From a Freertos task A:

      Source Code

      1. m_hMemDev = GUI_MEMDEV_CreateEx(0,0,DISPLAY_WIDTH_PIXELS,DISPLAY_HEIGHT_PIXELS, GUI_MEMDEV_NOTRANS);
      2. if ( 0 == m_hMemDev )
      3. {
      4. LOGGER_LOG_ERROR( LOG_CLASS, "%s: Could not create memdev", __FUNCTION__ );
      5. l_nResult = e_RETURNVALUE_Failure;
      6. goto lbl_err;
      7. }
      8. GUI_MEMDEV_Select(m_hMemDev);
      9. // debug test, this works fine, just adding stuff from the other thread
      10. GUI_Clear();
      11. {
      12. volatile void * mypointer;
      13. mypointer = GUI_MEMDEV_GetDataPtr( m_hMemDev );
      14. GUI_Clear();
      15. }
      Display All


      Then some other code runs, and finally from a different freertos task I do again
      GUI_Clear();

      and i get a hardfault.

      Debugger further the point where it goes wrong gives me a call stack:
      GUI_Clear -> WL__InitIVRSearch -> GUI_ALLOC_UnlockH

      GUI_ALLOC_UnlockH contains on the 7th line in assembler the instruction:
      LDRB.W R3, [R0, R5, LSL #3]

      This is passed 3 times correctly with R3 having value 0x6804003C
      Then a 4th time correctly with R3 being 0x68040074
      And then the 5th time R3 is 0x00000009 which of course causes the hard fault.

      ( 0x6804xxxx is all inside the extmem buffer passed on to emwin)

      Any suggestions what might be going wrong ?
      I dumped the complete contents of the extMem buffer passed to emwin to see if maybe something got corrupted there, and the only difference i have is that at the end of region some 0x0000 is replaced by 0x1841, which happens during the execution of GUI_MEMDEV_GetDataPtr.
      :10FF0000345D01200000000000000000000000003F
      becomes
      :10FF0000345D0120000000001841002000000000C6
      (intel hex format, offset 0 is start of the extMem buffer)
      I even tried clearing that to 0000 again but this did not solve the problem, so i am guessing it is totally unrelated and the problem is not some memory corruption.

      It seem/might be related to the fact that i call the function from a different thread (?). Is that no allowed for some reason ?

      Sideremark: the problem seems similar to emWin with external SRAM error, though maybe that one had a different cause(no thread relation ?)

      Thanks,
      Bram
    • Hi Bram,

      Is GUI_OS defined to 1 in the GUIConf.h?

      If this is defined to 0 or not defined (which is the same as defining it to 0) it is not allowed to call emWin from multiple tasks.

      If it is defined to 1 avoid calling GUI_Exec()/GUI_Delay() from multiple tasks. Only one task should call these functions.

      Not sure what exactly you are doing with memory device pointer, but might it be possible that you overwrite memory at some point?

      Regards,
      Sven
    • Hi Sven,

      GUI_OS is set to 1.
      GUI_MAXTASK is not defined. Manual says the default is 4. I have more tasks in my system but I am only calling it from 2 tasks now.
      The
      * GUI_X_GetTime()
      * GUI_X_Delay(int)

      * GUI_X_InitOS()
      * GUI_X_GetTaskId()
      * GUI_X_Lock()
      * GUI_X_Unlock()

      * GUI_X_GetTaskId
      * GUI_X_WaitEvent
      * GUI_X_SignalEvent
      functions have an implementation (provided by ST, if you think these may be involved i can go start checking them)

      I am actually not calling GUI_Exec/GUI_Delay at all at the moment, is that be a problem ?
      The only function I currently plan to use at the moment is to display text, some primitive drawing functions possibly later.
      (GUI_Exec is not even in the map file , the compiler pruned it out)

      I was not doing anything with the pointer yet (it was a local variable), but to check for possible corruptions (who knows, maybe some other task was writing incorrectly in emwin memory) I did the memory compare of the region passed to emwin before and I only had one difference (see previous post) resulting from the GUI_MEMDEV_GetDataPtr operation.

      Nevertheless, i now simplified my test scenario even more, I just do a GUI_MEMDEV_Select(m_hMemDev) + GUI_Clear() from one thread, and then a GUI_Clear from another thread.
      If I dumpe the extMem region before the calls, they are identical.
      But i still have a problem but at a slightly different location this time.
      The call stack is now :
      GUI_Clear -> LCD_FillRect -> _FillRect -> _memset16
      And it crashes because R0 (the first argument ) contains some bogus address (in de correct case it contains an address of the memdevice region).

      I see that the incorrect address is derived from calling GUI_ALLOC_LockH earlier, which I think should return addresses inside the extMem region, but in the erronous case it returns 0x00000009 (again the value 9, the same as in the original error).

      Does emwin store state information at some other place than the memory region passed to it ?
      If not , then the only difference between the 2 calls is the fact that the second call happens from a different thread (?)
      What is the functionality of the GUI_ALLOC_LockH functions


      Regards
      Bram
    • Hi,

      BramPeeters wrote:

      I just do a GUI_MEMDEV_Select(m_hMemDev) + GUI_Clear() from one thread, and then a GUI_Clear from another thread.
      Did you unselect the memory device after GUI_Clear()?

      Like:

      C Source Code

      1. GUI_MEMDEV_Select(m_hMemDev);
      2. GUI_Clear();
      3. GUI_MEMDEV_Select(0);

      BramPeeters wrote:

      Does emwin store state information at some other place than the memory region passed to it ?
      No, emWin uses only the memory block passed to it in GUI_X_Config().

      BramPeeters wrote:

      What is the functionality of the GUI_ALLOC_LockH functions
      GUI_ALLOC_LockH() marks a memory block as in use and uses the handle to return a pointer to some memory.

      Regards,
      Sven
    • Sven wrote:

      Did you unselect the memory device after GUI_Clear()
      Aha, no I did not !

      What I do now is :
      m_hMemDev = GUI_MEMDEV_CreateEx(0,0,DISPLAY_WIDTH_PIXELS,DISPLAY_HEIGHT_PIXELS, GUI_MEMDEV_NOTRANS)
      GUI_MEMDEV_Select(m_hMemDev);

      from my initialization thread to setup the memdev.

      And then the other threads that need to do something with the display would do:
      - Get the pointer with GUI_MEMDEV_GetDataPtr( m_hMemDev ) and fill the raw memory directly if needed
      - Do drawing actions like GUI_DispStringAt if needed

      - Put the image on the LCD with GUI_MEMDEV_CopyToLCD


      Actions towards the display are protected by a mutex at my level (i am guessing there is also thread safety to at emwin level with a mutex/semaphore looking at the os wrapper functions).


      But from your comment i conclude then that I should add a select/unselect around each memdev action ?

      So a memdev can only be selected by one thread at a time, is that the limitation ?


      Regards

      Bram
    • Hi,

      Try the code below, on my end this works fine. In MainTask() I create a memory device and a second task. I just save the handle of the memory device in a global variable. The second task uses the handle to get the device pointer and write raw color information into it.

      The second task writes a string directly to the screen and the first one write a string into the memory devices. Both tasks writiting the device to the screen.

      C Source Code

      1. #include "DIALOG.h"
      2. #include "RTOS.h"
      3. /*********************************************************************
      4. *
      5. * Externals
      6. *
      7. **********************************************************************
      8. */
      9. /*********************************************************************
      10. *
      11. * Types
      12. *
      13. **********************************************************************
      14. */
      15. /*********************************************************************
      16. *
      17. * Defines
      18. *
      19. **********************************************************************
      20. */
      21. /*********************************************************************
      22. *
      23. * Static data
      24. *
      25. **********************************************************************
      26. */
      27. static OS_STACKPTR int Stack1[768]; /* Task stack */
      28. static OS_TASK TCB1; /* Task-control-block */
      29. GUI_MEMDEV_Handle hMem;
      30. /*********************************************************************
      31. *
      32. * Static code
      33. *
      34. **********************************************************************
      35. */
      36. /*********************************************************************
      37. *
      38. * Task2
      39. */
      40. static void Task2(void) {
      41. GUI_COLOR aColor[] = {GUI_RED, GUI_GREEN, GUI_BLUE};
      42. static int Index;
      43. U32 * pData;
      44. int xSize;
      45. int ySize;
      46. int x;
      47. int y;
      48. while (1) {
      49. xSize = LCD_GetXSize();
      50. ySize = LCD_GetYSize();
      51. pData = (U32 *)GUI_MEMDEV_GetDataPtr(hMem);
      52. for (y = 0; y < ySize; y++) {
      53. for (x = 0; x < xSize; x++) {
      54. *pData = aColor[Index];
      55. pData++;
      56. }
      57. }
      58. GUI_MEMDEV_CopyToLCD(hMem);
      59. GUI_GotoXY(0, 0);
      60. GUI_DispString("Task2");
      61. Index++;
      62. Index = (Index == (int)GUI_COUNTOF(aColor)) ? 0 : Index;
      63. GUI_Delay(1000);
      64. }
      65. }
      66. /*********************************************************************
      67. *
      68. * Public code
      69. *
      70. **********************************************************************
      71. */
      72. /*********************************************************************
      73. *
      74. * MainTask
      75. */
      76. void MainTask(void) {
      77. GUI_Init();
      78. hMem = GUI_MEMDEV_CreateFixed32(0, 0, LCD_GetXSize(), LCD_GetYSize());
      79. OS_CREATETASK(&TCB1, "Task2", Task2, 100, Stack1);
      80. while (1) {
      81. GUI_MEMDEV_Select(hMem);
      82. GUI_GotoXY(0, 0);
      83. GUI_DispString("Task1");
      84. GUI_MEMDEV_Select(0);
      85. GUI_MEMDEV_CopyToLCD(hMem);
      86. GUI_Delay(1000);
      87. }
      88. }
      89. /*************************** End of file ****************************/
      Display All

      Regards,
      Sven
    • I assume in your Task2 if you would have wanted the
      1. GUI_GotoXY(0, 0);
      2. GUI_DispString("Task2");
      to be run on the memdev and not directly on the screen that you would have put a GUI_MEMDEV_Select(hMem); / GUI_MEMDEV_Select(0); around it right ?


      I have 'guarded' all my functions with these calls now and that seems to work without any further crashes :).
      Thanks !
      (maybe tell the person(s) responsible for the manual to add a note about this in the GUI_MEMDEV_Select documentation ? )



      The problem i face now is that my colors are incorrect when writing my raw images in the memdev and transferring them to the LCD.
      I know the raw images are generated 'correctly' in the format the LCD controller expects because i already used to write them directly to the LCD controller before i was using (st)emwin and they were fine.
      So somehow going via (st)emwin memdev mysteriously changed the colors ?
      I am going to check what the buffer passed via pfWriteM8_A1 looks like....
    • Hi,


      BramPeeters wrote:

      to be run on the memdev and not directly on the screen that you would have put a GUI_MEMDEV_Select(hMem); / GUI_MEMDEV_Select(0); around it right ?
      Exactly.

      BramPeeters wrote:

      (maybe tell the person(s) responsible for the manual to add a note about this in the GUI_MEMDEV_Select documentation ? )
      Actually, I'm the one ;) I will add a note to the manual.

      BramPeeters wrote:

      The problem i face now is that my colors are incorrect when writing my raw images in the memdev and transferring them to the LCD.

      If calling GUI_MEMDEV_Create() the memory device will be created with the color conversion used in your LCDConf.c (e.g. you set up the GUIDRV_FlexColor with GUICC_565, the memory device will also use it). You can create a memory device also with another color conversion. Just refer to the description of GUI_MEMDEV_CreateFixed().

      Try another color conversion or swap the bits when writing into the device.

      Which format are you using when writing to the device?

      Regards,
      Sven
    • Sven wrote:

      Actually, I'm the one [img]https://forum.segger.com/wcf/images/smilies/wink.png[/img] I will add a note to the manual.
      Haha, of course, there can be only one. Thanks :P


      Now looking at the buffers for my little color problem I see 2 issues:

      1. The memdev region (0x6804008c) is NOT passed directly to the low level function, it seems and intermediate 256 byte buffer (0x6804f674) is used. This is hugely unfortunate, given my attempt to do this whole operation without extra (useless) memcopy actions. So, bummer :/

      2. And more problematic is that I assume there is some kind of endiannes swapping (?) going on while moving the data from the memdev memory area to the intermediate byte buffer. In attachment a screenshot of both memory buffers, on the left is the original memdev memory area, on the right is the buffer argument passed to pfWriteM8_A1. My image starts with 00 C3 00 C3 etc etc, but for clarity i replaced the first bytes with ab cd ef. In the pfWriteM8_A1 buffer the bytes have been swapped around (which of course results in different colors).


      So .... the cache solution then ? Or will it also go via the intermediate swapped buffer ?

      Or is there a way to disable this byte swapping intermediate buffer maybe ?


      I currently use GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709 , GUIDRV_FLEXCOLOR_M16C0B8);

      I have 16 bit color data (format 565) going over an 8 bit bus to my external controller.


      Maybe if I use GUIDRV_FLEXCOLOR_M16C0B16 and implement the 16 bit version of the functions I will get the 16 bit unswapped ? And maybe the intermediate buffer is only used because of this swapping ?
      Images
      • MemDevNotUsed.jpg

        149.62 kB, 937×360, viewed 13 times
    • Small update: If I use GUIDRV_FLEXCOLOR_M16C0B16 I get pointers directly inside the memdev region so that is nice.
      There is a lot of tricky stuff going on though to get it right.
      Eg to set CASET values of the controller in 8 bit mode the following values are transferred : { 0x00, 0x00, 0x00, 0x7F }

      Now in 16 bit mode, he still transfers this (calling the functions 4 times), instead of only 2 times { 0x0000, 0x007F }
      This means that in my pfWrite16_A1 function i have to throw away the upper byte (and keep my fingers crossed that emwin never puts something useful in there).

      With this my raw image is now displayed correctly.
      I only fear that if i now use the drawing functions those colors will be swapped since it looks like internally emwin uses swapped bytes versus the transfer order towards the controller.
      I see there is a LCD_ENDIAN_BIG that might be related to that but it is a compile time constant, and not controller dependend ?

      Anyway i would have to regenerate all my raw images with 'swapped' bytes, and change the order of transmission in pfWriteM16_A1 to compensate. Not ideal but not the end of the world either.
    • So it is as I expected. If I use the 16 bit interface I get the memdev memory area directy in the low level functions without swapping.
      And I can transmit the bytes in the order so that my raw images have the right colors, but then any drawing actions I do (st)emwin will have the wrong colors.

      Eg if I fill the screen with red (RGB: 255,0,0), then the memdev memory area contains 1E 00 1 00 1E 00 (etc) resulting in a green screen if i transmit the bytes in that order to the LCD controller. (note: the 0x1E and not 0x1F is probably because i already do some color conversions losing some LSB bits)

      Will changing the LCD_ENDIAN_BIG define lead to a memdev area containing f8 00 f8 00 f8 00 ?
      Or will it leave the order in memory unchanged and only activate or deactive the swapping function at the moment the bytes are transmitted to the screen?

      EDIT: actually the 1E 00 (or 1F 00) is unexpected too, if i fill the screen with red i would have expected the memory area to contain 0x00 0xF8 bytes, so probably the byte swapping is only 1 of my issues
      EDIT2: Ok, the 1E 00 instead of the 00 F8 is controlled by the GUICC_565 -> GUICC_M565 parameter

      The post was edited 3 times, last by BramPeeters ().