648 views
in System Integration by

Hello,

I'm here to ge the SPI on LIZARDBOARD to work, so i'll explain in detail my configuaration.

In my Application folder i defined a Device Block, compreensive of DeviceClass, Device Auto object and Hardaware includes wrote in the Inline Block.

in the Inline Block i placed my code, with a device driver i wrote based on the HAL library, as it is a STM32 powered board.

in that i wrote includes, an instance of the spi handle i want to implement and an array of value for the SPI to send.

/*

  TO DO:

  Include external header files or add type and function declarations needed
  in the implementation of Application::DeviceClass. For example:

    #include "DeviceDriver.h"

    #include "your_middleware_api.h"

    void Your_Middleware_Some_Function( int aSomeArg );

*/

#include "SINERGO_bsp.h"
#include "stdbool.h"

SPI_HandleTypeDef hspi2;

uint8_t buffer_send[4]= {3,2,1,0};

I created a GUI application where a basic screen calls other screens with command  " this.PresentDialog( new Application::BootScreen, null, null, null, null, null, null, null, null, false );" and declared a var to instance a device, so it gets initialized and can be called from other screens, in the init method of the basic screen.

in the init method of the device, i put peripheral init code of the STM32 mcu, copied from STM32 cube MX generated code, in particular for SPI

 

// pass the hspi2 i declared in the inline code metioned when declaring the device block 

void SinergoFunc_Spi_Init(SPI_HandleTypeDef spiP) 
{
  /* SPI2 parameter configuration*/
  spiP.Instance = SPI2;
  spiP.Init.Mode = SPI_MODE_MASTER;
  spiP.Init.Direction = SPI_DIRECTION_2LINES;
  spiP.Init.DataSize = SPI_DATASIZE_8BIT;
  spiP.Init.CLKPolarity = SPI_POLARITY_LOW;
  spiP.Init.CLKPhase = SPI_PHASE_1EDGE;
  spiP.Init.NSS = SPI_NSS_HARD_OUTPUT;
  spiP.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  spiP.Init.FirstBit = SPI_FIRSTBIT_MSB;
  spiP.Init.TIMode = SPI_TIMODE_DISABLE;
  spiP.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  spiP.Init.CRCPolynomial = 10;


  if (HAL_SPI_Init(&spiP) == HAL_OK)
  {
   HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_7); // bottom led for debug, it works so gpio it's ok and the configuration is ok hal returns ok state after configuartion
  }
}

//the HAL_SPI_Init gets called from HAL libraries but needs the implementetion fo hal msp to set gpio for spi peripheral.



void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */

  /* USER CODE END SPI2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PB9     ------> SPI2_NSS
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI2_MspInit 1 */

  /* USER CODE END SPI2_MspInit 1 */
  }

}

Assuming initialization is ok, i want to get a error state displayed on the display, so in the home screen, i get a print of the error.

When clicking toggle button i send the command to spi to send. the command returns the error and displays it.

Here the methods in the device.

the init method.

// The following section is intended to perform initialization-related operations
// in the underlying device or middleware. Consequently, the section is taken in
// account only when generating code (not during prototyping).
$if !$prototyper
  var object thisObject = this;


  /*
     TO DO:

     The following native statement is intended to enclose code to communicate with
     your device API. The variable 'thisObject' contains a pointer to the actually
     initialized Application::DeviceClass object. Use the 'thisObject' pointer to
     e.g. register the object by the middleware as receiver of events, etc.
     
  */

  native ( thisObject )
  {
    /*
       TO DO:

       Depending on your application case you call functions of the underlying
       middleware (or access the device directly) in order to perform the necessary
       initialization steps. For example, you invoke some 'C' function:

       */



        SinergoFunc_GPIO_Init();

        SinergoFunc_Spi_Init(hspi2);


       /*

       The variable 'thisObject' represents the actually initialized instance of the
       Application::DeviceClass. You can store this variable e.g. in the middleware
       and use it whenever the middleware needs to notify the GUI application about
       some state alternation or events. In this manner, the middleware will be able
       to invoke methods of the interface device object.

       For example, you can store 'thisObject' in some global C variable:

         // Declaration of the global C variable
         XObject theDeviceObject;

         // Store the instance in the global variable
         theDeviceObject = thisObject;

       Later use the global variable e.g. to provide the GUI application with events:

         ApplicationDeviceClass__TriggerSomeEvent( theDeviceObject );

       IMPORTANT:
       ----------

       If you store 'thisObject' for later use, don't forget to implement the opposite
       operation in the method 'Done'. Concrete, 'Done' should set the global variable
       again to the value NULL.

    */
  }
$endif

and the command method SPIsend:

$if !$prototyper
var uint8 send_result=7; // random value

  native (send_result)
  {
      send_result = HAL_SPI_Transmit(&hspi2,&buffer_send[0], 1, 0);
      if((send_result =! HAL_OK))
      {
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7,GPIO_PIN_SET);
      }
  }
return send_result;
  
 $endif

 

the method called by the onActivate of the buttton is :

 

sender; /* the method is called from the sender object */


// toggle of a LED to debug a respons from hardware and show a rectangle


Application::Device.LED_STATE =! Application::Device.LED_STATE;

Application::Device.Led_Switch(Application::Device.LED_STATE );
Rectangle.Visible= Application::Device.LED_STATE;

//Display the error return from the send method of spi

ValueDisplay.CurrentValue=Application::Device.SPI_Send();

 

So.... i'm stuck on getting an SPI error 1 ( HAL_ERROR) when calling the SPI_Transmit command, it returns HAL_Error an toggles and led for debug.

Could be the cause of the command not reaching the array to send? configuration wise is corret the code or the idea of implementation? (EDIT: put the array declaration right above the spi_transmit call, same error)

 

Thanks.

1 Answer

0 votes
by
Hello Riccardo,

let me recommend to make some redesign in your architecture: Try to separate the GUI application from your SPI functions. This means, you should define a certain 'C' API, that covers completely your SPI protocol (or whatever protocol), so that the GUI application just get an access to some underlying machine, without any SPI details.

Let's assume you have a 'C' interface like YourDriver_Init(), YourDriver_Done(), YourDriver_SetData(), ... This API can be fully tested using a simple C program.

Then you can implement your GUI application, which operates in the first step with dummy data, and in a later step the real data from the device can be used.

Currently, you put some SPI and GPIO details within the GUI application as native code section - so you have to generate code each time you want to change some hardware related things. Please have a look to the example DeviceIntegration that is provided within the example folder of the Build Environment. All GPIO or ADC stuff is done in the 'C' module - the GUI application is just using events or data from the hardware.

Best regards,

Manfred.
by
Thanks, Manfred.

But how this astraction of the underlyng hardware  could benefit the application? I understand that every time i need to generate code, but the first poin is to get the HW to work, then  i could perfection it.

I assumed the native statment was for this type of purpose, calling underlyng functions and variabled.

thsnk vey much
by

Hi Riccardo,

of course, you can put whatever code into a native section - it is just copied as it is into the generated code. The separation between GUI and underlying machine is helpful to have a clear API and a software layer that can be tested separately.

Anyhow - what could cause the problem? Maybe you can check the following:

Do you have a variable within your application class that refers to the Device class? 

This is essential to avoid that the Device is not de-initialized and initialized again and again. See lifetime of autoobjects.

Second, you can check if the 'hspi2' that you are using within the native code is the same that you are using in your C code.

Best regards,

Manfred.

by

Do you have a variable within your application class that refers to the Device class? 

Yes, i defined it in the base screen init method, so the istance of the device is initiated and it is accesible from the screens related to it.

 you can check if the 'hspi2' that you are using within the native code is the same that you are using in your C code.

The SPI_HandleTypeDef hspi2 is inserted in the inline code of the device block, in the application folder. it is a the bottom so in the Application. C is inserted right afer EW includes 

 

/*******************************************************************************
*
* E M B E D D E D   W I Z A R D   P R O J E C T
*
*                                                Copyright (c) TARA Systems GmbH
*                                    written by Paul Banach and Manfred Schweyer
*
********************************************************************************
*
* This file was generated automatically by Embedded Wizard Studio.
*
* Please do not make any modifications of this file! The modifications are lost
* when the file is generated again by Embedded Wizard Studio!
*
* The template of this heading text can be found in the file 'head.ewt' in the
* directory 'Platforms' of your Embedded Wizard installation directory. If you
* wish to adapt this text, please copy the template file 'head.ewt' into your
* project directory and edit the copy only. Please avoid any modifications of
* the original template file!
*
* Version  : 12.03
* Profile  : Profile
* Platform : STM.STM32.RGB565
*
*******************************************************************************/

#include "ewlocale.h"
#include "_ApplicationBootScreen.h"
#include "_ApplicationDeviceClass.h"
#include "_ApplicationFullStackGui.h"
#include "_ApplicationHomeScreen.h"
#include "_ApplicationScreenBase.h"
#include "_ApplicationSettingScreen.h"
#include "_CoreGroup.h"
#include "_CoreView.h"
#include "_EffectsInt32Effect.h"
#include "_EffectsSlideTransition.h"
#include "_EffectsTransition.h"
#include "_ResourcesBitmap.h"
#include "_ResourcesFont.h"
#include "_ViewsImage.h"
#include "_ViewsRectangle.h"
#include "_ViewsText.h"
#include "_WidgetSetPushButton.h"
#include "_WidgetSetPushButtonConfig.h"
#include "_WidgetSetValueDisplay.h"
#include "_WidgetSetValueDisplayConfig.h"
#include "Application.h"
#include "Core.h"
#include "Resources.h"
#include "Views.h"
#include "WidgetSet.h"

/* Compressed strings for the language 'Default'. */
EW_CONST_STRING_PRAGMA static const unsigned int _StringsDefault0[] =
{
  0x000000C4, /* ratio 69.39 % */
  0xB8000F00, 0x80084452, 0x00C60030, 0x21A00358, 0x88458183, 0x0740041C, 0x2F001940,
  0x90015000, 0x8B1B4006, 0x8038010D, 0x1B226438, 0x00C4008E, 0x62B13390, 0xDC0037C7,
  0x9100AC84, 0x679944C9, 0x9899D400, 0x000822F3, 0xBC9E4053, 0x0025D0A8, 0x361B3298,
  0x6611B880, 0x01439CCE, 0x9179B4FC, 0x1005C84C, 0x68AC5E83, 0x39802714, 0x2C401521,
  0x4C2CB2B2, 0x36C51796, 0x22F10044, 0x4367964B, 0x00080DCA, 0x00000000
};

/* Constant values used in this 'C' module only. */
static const XRect _Const0000 = {{ 0, 0 }, { 800, 480 }};
static const XRect _Const0001 = {{ 481, 16 }, { 778, 48 }};
static const XColor _Const0002 = { 0x00, 0x00, 0x00, 0xFF };
static const XRect _Const0003 = {{ 252, 224 }, { 549, 256 }};
static const XRect _Const0004 = {{ 21, 78 }, { 171, 128 }};
static const XStringRes _Const0005 = { _StringsDefault0, 0x0002 };
static const XRect _Const0006 = {{ 198, 78 }, { 588, 128 }};
static const XStringRes _Const0007 = { _StringsDefault0, 0x0009 };
static const XRect _Const0008 = {{ 198, 128 }, { 588, 178 }};
static const XStringRes _Const0009 = { _StringsDefault0, 0x0015 };
static const XRect _Const000A = {{ 198, 178 }, { 588, 228 }};
static const XStringRes _Const000B = { _StringsDefault0, 0x0023 };
static const XRect _Const000C = {{ 460, 103 }, { 644, 203 }};
static const XColor _Const000D = { 0xFF, 0x3B, 0x2D, 0xFF };
static const XRect _Const000E = {{ 477, 128 }, { 627, 178 }};
static const XStringRes _Const000F = { _StringsDefault0, 0x0038 };
static const XRect _Const0010 = {{ 477, 279 }, { 627, 329 }};
static const XStringRes _Const0011 = { _StringsDefault0, 0x0045 };
static const XRect _Const0012 = {{ 100, 103 }, { 297, 220 }};
static const XStringRes _Const0013 = { _StringsDefault0, 0x0050 };
static const XRect _Const0014 = {{ 100, 204 }, { 300, 236 }};
static const XStringRes _Const0015 = { _StringsDefault0, 0x005A };

/* User defined inline code: 'Application::SINERGO_bsp' */
/*

  TO DO:

  Include external header files or add type and function declarations needed
  in the implementation of Application::DeviceClass. For example:

    #include "DeviceDriver.h"

    #include "your_middleware_api.h"

    void Your_Middleware_Some_Function( int aSomeArg );

*/

#include "SINERGO_bsp.h"
#include "stdbool.h"

SPI_HandleTypeDef hspi2;              //<--------------------------here

So i'm sure it is defined and available.

I can share my project with you if needed.

 

Thanks

by
Please share your project - otherwise it will be very difficult...
by

Hi Riccardo,

thanks for sending the project. Unfortunately, it is not complete, because there are references to resources that are stored on your desktop. 

Anyhow, please review your implementation of your SPI_Send() method:

Can you try

if ( send_result != HAL_OK )

instead of

if((send_result =! HAL_OK))

then it will return the original result... I assume you have got some compiler warnings - right?

Let me recommend once more to have a clear software structure without moving STM32Cube firmware details into a GUI project.

I hope this helps.

Best regards,

Manfred.

by

Yes the missing resource might be the images of the backscreen. 

I get oly warnings about the unused object of the device

 

Entering Embedded Wizard template project


C:\STM32\STM32F469-LIZARD\Application\Project\GCC>build
"build" non รจ riconosciuto come comando interno o esterno,
 un programma eseguibile o un file batch.

C:\STM32\STM32F469-LIZARD\Application\Project\GCC>make
-------------------------------------------------
Creating EmbeddedWizard-STM32F469-LIZARD
-------------------------------------------------
Compiler Options: -O2 -Wall -mcpu=cortex-m4 -mlittle-endian -mthumb -mthumb-interwork -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -DUSE_HAL_DRIVER -DSTM32F469xx -DEW_FRAME_BUFFER_COLOR_FORMAT=EW_FRAME_BUFFER_COLOR_FORMAT_RGB565 -DEW_SURFACE_ROTATION=0 -DEW_USE_OPERATING_SYSTEM=1
-------------------------------------------------
Creating object and binary directories
-------------------------------------------------
Compiling ../../GeneratedCode/Application.c
../../GeneratedCode/Application.c: In function 'ApplicationDeviceClass_Done':
../../GeneratedCode/Application.c:715:11: warning: unused variable 'thisObject' [-Wunused-variable]
  715 |   XObject thisObject = ((XObject)_this );
      |           ^~~~~~~~~~
../../GeneratedCode/Application.c: In function 'ApplicationDeviceClass_Init':
../../GeneratedCode/Application.c:743:11: warning: variable 'thisObject' set but not used [-Wunused-but-set-variable]
  743 |   XObject thisObject;
      |           ^~~~~~~~~~
Linking EmbeddedWizard-STM32F469-LIZARD
arm-none-eabi-gcc -mcpu=cortex-m4 -mlittle-endian -mthumb -mthumb-interwork -mfpu=fpv4-sp-d16 -mfloat-abi=hard -Wl,--gc-sections -Wl,-Map=./Bin/EmbeddedWizard-STM32F469-LIZARD.map ./startup_stm32f469xx.s              ./Obj/main.o
   ./Obj/ewmain.o              ./Obj/DeviceDriver.o         ./Obj/Core.o         ./Obj/Effects.o         ./Obj/Graphics.o         ./Obj/Resources.o         ./Obj/Views.o         ./Obj/Application.o         ./Obj/Templates.o         ./Obj/WidgetSet.o         ./Obj/ewextrte.o         ./Obj/ewextgfx.o     ./Obj/ew_bsp_os.o     ./Obj/ew_bsp_system.o     ./Obj/ew_bsp_clock.o     ./Obj/ew_bsp_event.o     ./Obj/ew_bsp_display.o     ./Obj/ew_bsp_touch.o     ./Obj/ew_bsp_console.o     ./Obj/ew_bsp_inout.o     ./Obj/ew_bsp_graphics.o     ./Obj/stm32f4xx_it.o     ./Obj/system_stm32f4xx.o              ./Obj/stm32f4xx_hal.o              ./Obj/stm32f4xx_hal_rcc.o              ./Obj/stm32f4xx_hal_rcc_ex.o              ./Obj/stm32f4xx_hal_cortex.o              ./Obj/stm32f4xx_hal_gpio.o              ./Obj/stm32f4xx_hal_sdram.o              ./Obj/stm32f4xx_hal_dma.o              ./Obj/stm32f4xx_hal_ltdc.o              ./Obj/stm32f4xx_hal_dma2d.o              ./Obj/stm32f4xx_hal_i2c.o              ./Obj/stm32f4xx_hal_i2c_ex.o              ./Obj/stm32f4xx_hal_dsi.o              ./Obj/stm32f4xx_hal_uart.o              ./Obj/stm32f4xx_hal_pcd.o              ./Obj/stm32f4xx_hal_pcd_ex.o              ./Obj/stm32f4xx_hal_pwr.o              ./Obj/stm32f4xx_hal_pwr_ex.o              ./Obj/stm32f4xx_hal_tim.o              ./Obj/stm32f4xx_hal_tim_ex.o              ./Obj/stm32f4xx_hal_rtc.o              ./Obj/stm32f4xx_hal_rtc_ex.o
./Obj/stm32f4xx_ll_fmc.o              ./Obj/stm32f4xx_ll_usb.o              ./Obj/stm32f4xx_hal_qspi.o              ./Obj/stm32f4xx_hal_spi.o              ./Obj/stm32f4xx_hal_msp.o              ./Obj/LIZARD.o              ./Obj/LIZARD_ts.o              ./Obj/LIZARD_sdram.o              ./Obj/LIZARD_pwm.o              ./Obj/LIZARD_qspi.o              ./Obj/SINERGO_bsp.o        ./Obj/list.o        ./Obj/queue.o        ./Obj/tasks.o        ./Obj/timers.o        ./Obj/cmsis_os.o        ./Obj/heap_4.o        ./Obj/port.o -L../../../PlatformPackage/RTE -L../../../PlatformPackage/RGB565 -lm -lc -lnosys -lewgfx-m4-gcc -lewrte-m4-gcc -T ./stm32f4_flash.ld -o ./Bin/EmbeddedWizard-STM32F469-LIZARD.elf
Memory Usage:
./Bin/EmbeddedWizard-STM32F469-LIZARD.elf  :
section                 size         addr
.isr_vector            0x1b4    0x8000000
.SectionEwResource   0x15778   0x90000000
.text                0x3cebc    0x80001c0
.rodata               0x72fc    0x803d07c
.ARM                     0x8    0x8044378
.init_array              0x4    0x8044380
.fini_array              0x4    0x8044384
.data                  0x490   0x20000000
.ccmram                  0x0   0x10000000
.bss                  0x4af0   0x20000490
._user_heap_stack     0x2200   0x20004f80
.ARM.attributes         0x30          0x0
.comment                0x57          0x0
.debug_info           0x524b          0x0
.debug_abbrev         0x1e23          0x0
.debug_loclists       0x3a36          0x0
.debug_aranges         0x408          0x0
.debug_rnglists        0x40d          0x0
.debug_line           0x4ec2          0x0
.debug_str            0x1c56          0x0
.debug_frame           0x6b8          0x0
.debug_line_str         0xcf          0x0
Total                0x73253


EmbeddedWizard-STM32F469-LIZARD successfully built !!

C:\STM32\STM32F469-LIZARD\Application\Project\GCC>

 

the modification you suggested not changed the situation.

Could it be that the embedded wizard gui is RTOS based, so i have to work with RTOS tasks and calling functions inside them instead?

Thanks

 

 

by

Hello,

you can use the provided Build Environment with or without FreeRTOS. You will find the flag at the beginning of the makefile. By default, the usage of FreeRTOS is enabled.

Please have a look to the example DeviceIntegration that is located in the folder /Examples/DeviceIntegration. It shows the implementation of a device interface without any hardware dependencies. The counterpart is shown in the file /Application/Source/DeviceDriver.c - there you will find the following functions:

DeviceIntegrationExample_Init()

DeviceIntegrationExample_Done()

DeviceIntegrationExample_SetLedStatus()

DeviceIntegrationExample_PrintMessage()

In principle you can follow the same approach. Instead of printing a message via UART you can start your SPI transfer. That's all.

I hope this example and the documentation helps to find your solution.

Best regards,

Manfred.

by

Hi Manfred,

We solved the problem, it was a pointer to the hspi structure not working properly.

Now all good.

On to the next problem! laugh

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...