S7G2 Using the LCD interface to control Blinking LED's

s7g2
e2studio
guix

#1


Introduction

BOARD : S7G2 7H3A01CFC
SSP : 1.2
e2 Studio : 5.4.0

  1. The purpose of this project was to integrate the external LEDS with the LCD. I wanted to connected a few LED’s and have the control switch at the LCD. I also integrated a gauge. The gauge controls the rate at which the lights blink. I connected LEDS in series with the Arduino Shield GPIO pins. As the user hits the plus key, the LEDS will light up one at a time with increased blink rate each time. The minus button decreases the blink rate. The number in the gauge tells the user the setting of the frequency. The LEDS will blink across the length of the five LEDs, just like the Knight Rider Car. The number buttons (1-5) on the LCD will control its respective LEDS, and the ON/OFF will either turn on all the LEDS or turn off. How to configure GPIO pins can be found in my previous tutorial.
    .
    This project had some challenges due to the integration of the HAL drivers and the LCD drivers. The biggest challenge was integrating the circular gauge and having it rotate a few degrees each time the buttons were clicked. This part of the project took lots of research, restarts, and many interactions with the Renesas Tech team. This brings me to the next point. The Renesas Team is phenomenal, and they will guide you through any technical difficulties encountered throughout the project. I had a series of emails throughout the days until the problem was solved.

  2. The problem
    I wanted a rotating gauge. For this to occur, we needed two things. The gauge face, and a needle. In order to rotate, the MCU has to designate and allocate a sizeable memory just for the rotating of the needle pixel map. First, I had to configure the D/AVE drivers, 2) I had to switch the configurations to SDRAM vs BSS 3) Decrease the size of the Heap and finally creates two different threads. One thread for Touch Screen and another for the GUI events. I also had to write a few lines of code that would dynamically point to and allocate the memory as the program was running…very painful process, but rewarding once achieved.

  3. Configuration
    Base project code on GitHub: https://github.com/elpaniagua/synergy_gauge_sks7





These are the main changes, everything else is the same as the “Hello World” configuration.

4.GUIX Construction
The main challenge was the rotating of the needle. This pixelmap has to be setup in a specific configuration. For the gauge , we create using INSERT-> INDICATOR->GAUGE. Once the gauge is inserted, we add a needle to the custom pixel map. Once the custom pixel map has a needle for the gauge, we must assign the gauge a needle pixelmap.
How do we assign a needle pixelmap to the gauge ? Under the properties windows of the gauge, go to “Needle Pixelmap” section and assign the name of the needle that was added in the “Custom Pixel Maps” section.

Adding the other button is pretty straight forward, there are previous tutorials that will have this in detail.

  1. Code Construction

Thanks to the Tech at Renesas, they facilitated the code construction for allocating the memory in order to rotate the needle and accomplish the threads at the same time. As seen in the code , the function *Void memory_allocate(ULONG size) is the function that points to the memory that will initialize this thread. Without this function, there will be no needle and blank screen. The next function is the Void memory_free function. This function de-allocates the memory once the rotation is complete so that other threads can function properly. As seen in the code construction, each button is assigned a light. The rotating gauge assigns the value of the speed at which the lights traverse, frequency of the blink. The buttons are 1,2,3,4,5 “+”, “-” and “On/Off”. The numbers will turn on the respective lights, the on/off will do just that, and the gauge sets the frequency speed.

//#define            SCRATCHPAD_PIXELS (MAIN_DISPLAY_X_RESOLUTION * MAIN_DISPLAY_Y_RESOLUTION)
#define            SCRATCHPAD_PIXELS (220 * 220)
GX_COLOR           scratchpad[SCRATCHPAD_PIXELS];
TX_BYTE_POOL       memory_pool;

GX_WINDOW_ROOT * p_window_root;
GX_WINDOW p_splash_screen;

GX_CHAR           plus_text[] = "+";
GX_CHAR           minus_text[] = "-";
uint32_t            i_temperature = 50;

void set_temperature_value(void);
void *memory_allocate(ULONG size);
void memory_free(VOID *mem);

void g_lcd_spi_callback(spi_callback_args_t * p_args);
static void guix_test_send_touch_message(sf_touch_panel_payload_t * p_payload);
const bsp_delay_units_t bsp_delay_units = BSP_DELAY_UNITS_MILLISECONDS;
uint32_t delay = 30;






void g_lcd_spi_callback(spi_callback_args_t * p_args)
{
    (void)p_args;
    tx_semaphore_ceiling_put(&g_gui_semaphore0, 1);
}

void guix_round_thermostat_thread_entry(void);

/******************************************************************************************/
void *memory_allocate(ULONG size)
{
    VOID *memptr;

    if (tx_byte_allocate(&memory_pool, &memptr, size, TX_NO_WAIT) == TX_SUCCESS)
    {
        return memptr;
    }
    return NULL;
}

/******************************************************************************************/
void memory_free(VOID *mem)
{
    tx_byte_release(mem);
}



/* GUIX Base Thread entry function */
void guix_round_thermostat_thread_entry(void)
{
ssp_err_t err;
    sf_message_header_t * p_message = NULL;
    UINT      status = TX_SUCCESS;
    /* Initializes GUIX. */
    status = gx_system_initialize();
    if(TX_SUCCESS != status)
    {
        while(1); //Debug trap
    }

    /* Initializes GUIX drivers. */
    err = g_sf_el_gx0.p_api->open (g_sf_el_gx0.p_ctrl, g_sf_el_gx0.p_cfg);
    if(SSP_SUCCESS != err)
    {
        while(1); //Debug trap
    }

    gx_studio_display_configure ( MAIN_DISPLAY,
                                  g_sf_el_gx0.p_api->setup,
                                  LANGUAGE_ENGLISH,
                                  MAIN_DISPLAY_THEME_1,
                                  &p_window_root );

    err = g_sf_el_gx0.p_api->canvasInit(g_sf_el_gx0.p_ctrl, p_window_root);
    if(SSP_SUCCESS != err)
    {
        while(1); //Debug trap
    }

    /* create byte pool for needle rotation to use */
    status = tx_byte_pool_create(&memory_pool, "scratchpad", scratchpad, SCRATCHPAD_PIXELS * sizeof(GX_COLOR));
    if(TX_SUCCESS != status)
    {
        while(1); //Debug trap
    }

    /* Creates the primary screen. */
    status = gx_studio_named_widget_create("splash_screen", (GX_WIDGET *)p_window_root, (GX_WIDGET **) &p_splash_screen);
    if(TX_SUCCESS != status)
    {
        while(1); //Debug trap
    }

    /* Shows the root window to make it visible. */
    status = gx_widget_show(p_window_root);
    if(TX_SUCCESS != status)
    {
        while(1); //Debug trap
    }

    /* Lets GUIX run. */
    status = gx_system_start();
    if(TX_SUCCESS != status)
    {
        while(1); //Debug trap
    }

    /* install our memory allocator and de-allocator */
    gx_system_memory_allocator_set(memory_allocate, memory_free);

    /** Open the SPI driver to initialize the LCD **/
    err = g_rspi_lcdc.p_api->open(g_rspi_lcdc.p_ctrl, g_rspi_lcdc.p_cfg);
    if(SSP_SUCCESS != err)
    {
        while(1); //Debug trap
    }

    /** Setup the ILI9341V **/
    ILI9341V_Init();


    while (1)
    {
        g_sf_message0.p_api->pend(g_sf_message0.p_ctrl, &guix_round_thermostat_thread_message_queue, (sf_message_header_t **) &p_message, TX_WAIT_FOREVER);
        switch (p_message->event_b.class_code)
        {
        case SF_MESSAGE_EVENT_CLASS_TOUCH:
            if (SF_MESSAGE_EVENT_NEW_DATA == p_message->event_b.code)
            {
                //sf_touch_panel_payload_t * p_touch_message = (sf_touch_panel_payload_t *) p_message;

                /** Translate a touch event into a GUIX event */
                guix_test_send_touch_message((sf_touch_panel_payload_t *) p_message);
            }
            break;
        default:
            break;
        }

        /** Message is processed, so release buffer. */
        err = g_sf_message0.p_api->bufferRelease(g_sf_message0.p_ctrl, (sf_message_header_t *) p_message, SF_MESSAGE_RELEASE_OPTION_NONE);
        if (err)
        {
            while(1); //Debug trap
        }
        tx_thread_sleep(1);
    }
}


/*******************************************************************************************************************//**
 * @brief  Sends a touch event to GUIX internal thread to call the GUIX event handler function
 *
 * @param[in] p_payload Touch panel message payload
***********************************************************************************************************************/
static void guix_test_send_touch_message(sf_touch_panel_payload_t * p_payload)
{
    bool send_event = true;
    GX_EVENT gxe;

    switch (p_payload->event_type)
    {
    case SF_TOUCH_PANEL_EVENT_DOWN:
        gxe.gx_event_type = GX_EVENT_PEN_DOWN;
        break;
    case SF_TOUCH_PANEL_EVENT_UP:
        gxe.gx_event_type = GX_EVENT_PEN_UP;
        break;
    case SF_TOUCH_PANEL_EVENT_HOLD:
    case SF_TOUCH_PANEL_EVENT_MOVE:
        gxe.gx_event_type = GX_EVENT_PEN_DRAG;
        break;
    case SF_TOUCH_PANEL_EVENT_INVALID:
        send_event = false;
        break;
    default:
        break;
    }

    if (send_event)
    {
        /** Send event to GUI */
        gxe.gx_event_sender         = GX_ID_NONE;
        gxe.gx_event_target         = 0;  /* the event to be routed to the widget that has input focus */
        gxe.gx_event_display_handle = 0;

        gxe.gx_event_payload.gx_event_pointdata.gx_point_x = (GX_VALUE)(p_payload->x);
        gxe.gx_event_payload.gx_event_pointdata.gx_point_y = (GX_VALUE)(320 - p_payload->y);

        gx_system_event_send(&gxe);
    }
}


/******************************************************************************************/
VOID custom_pixelmap_button_draw(GX_PIXELMAP_BUTTON *button)
{
INT      x_offset = 0;
INT      y_offset = 0;
GX_CHAR *text;

    gx_pixelmap_button_draw(button);


    switch (button->gx_widget_id)
    {
    case ID_PLUS_BTN:
        text = plus_text;
        break;

    case ID_MINUS_BTN:
        text = minus_text;
        break;

    }

    if (button->gx_widget_style & GX_STYLE_BUTTON_PUSHED)
    {
        x_offset++;
        y_offset++;
    }

    gx_widget_text_draw((GX_WIDGET *)button, GX_COLOR_ID_TEXT_INPUT_FILL,
                        GX_FONT_ID_BOLD, text,
                        x_offset, y_offset);
}

/******************************************************************************************/
void set_temperature_value()
{
GX_PROMPT *prompt;
static GX_CHAR str_value[10];

    prompt = &splash_screen.splash_screen_value_prompt;

    gx_utility_ltoa(i_temperature, str_value, 10);
    gx_prompt_text_set(prompt, str_value);
}

/* Splash Screen Event Handler */
/******************************************************************************************/
UINT SplashScreenEventHandler(GX_WINDOW *widget, GX_EVENT *event_ptr)
{
    GX_CIRCULAR_GAUGE *gauge;
    INT                angle;
    UINT      status;

    gauge = &splash_screen.splash_screen_gauge;

    switch(event_ptr->gx_event_type)
    {


        case GX_SIGNAL(ID_MINUS_BTN, GX_EVENT_CLICKED):
            gx_circular_gauge_angle_get(gauge, &angle);

            if (angle > -185)
            {
                status = gx_circular_gauge_angle_set(gauge, angle - 5);
                i_temperature--;
                set_temperature_value();

                for(int i = 0; i < 2; i++)
                {

                       g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_07,IOPORT_LEVEL_HIGH);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);
                       g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_07,IOPORT_LEVEL_LOW);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);

                       g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_06,IOPORT_LEVEL_HIGH);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);
                       g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_06,IOPORT_LEVEL_LOW);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);

                       g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07,IOPORT_LEVEL_HIGH);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);
                       g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07,IOPORT_LEVEL_LOW);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);

                       g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_14,IOPORT_LEVEL_HIGH);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);
                       g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_14,IOPORT_LEVEL_LOW);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);

                       g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_13,IOPORT_LEVEL_HIGH);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);
                       g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_13,IOPORT_LEVEL_LOW);
                       R_BSP_SoftwareDelay(i_temperature+10, bsp_delay_units);
                }
            }
            break;






    case GX_SIGNAL(ID_PLUS_BTN, GX_EVENT_CLICKED):
        gx_circular_gauge_angle_get(gauge, &angle);
        if (angle < 90)
        {
            status = gx_circular_gauge_angle_set(gauge, angle + 5);
            i_temperature++;
            set_temperature_value();
            for(int i = 0; i < 2; i++)
            {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_07,IOPORT_LEVEL_HIGH);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);
                   g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_07,IOPORT_LEVEL_LOW);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);

                   g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_06,IOPORT_LEVEL_HIGH);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);
                   g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_06,IOPORT_LEVEL_LOW);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);

                   g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07,IOPORT_LEVEL_HIGH);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);
                   g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07,IOPORT_LEVEL_LOW);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);

                   g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_14,IOPORT_LEVEL_HIGH);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);
                   g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_14,IOPORT_LEVEL_LOW);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);

                   g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_13,IOPORT_LEVEL_HIGH);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);
                   g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_13,IOPORT_LEVEL_LOW);
                   R_BSP_SoftwareDelay(i_temperature-10, bsp_delay_units);
            }
        }
        break;
    case GX_SIGNAL(ID_ONE, GX_EVENT_TOGGLE_ON):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_07,IOPORT_LEVEL_HIGH);

        }
    break;

    case GX_SIGNAL(ID_ONE, GX_EVENT_TOGGLE_OFF):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_07,IOPORT_LEVEL_LOW);

        }
        break;
    case GX_SIGNAL(ID_TWO, GX_EVENT_TOGGLE_ON):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_06,IOPORT_LEVEL_HIGH);

        }
    break;

    case GX_SIGNAL(ID_TWO, GX_EVENT_TOGGLE_OFF):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_06,IOPORT_LEVEL_LOW);

        }
        break;
    case GX_SIGNAL(ID_THREE, GX_EVENT_TOGGLE_ON):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07,IOPORT_LEVEL_HIGH);

        }
    break;

    case GX_SIGNAL(ID_THREE, GX_EVENT_TOGGLE_OFF):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07,IOPORT_LEVEL_LOW);

        }
        break;

    case GX_SIGNAL(ID_FOUR, GX_EVENT_TOGGLE_ON):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_14,IOPORT_LEVEL_HIGH);

        }
    break;

    case GX_SIGNAL(ID_FOUR, GX_EVENT_TOGGLE_OFF):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_14,IOPORT_LEVEL_LOW);

        }
        break;

    case GX_SIGNAL(ID_FIVE, GX_EVENT_TOGGLE_ON):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_13,IOPORT_LEVEL_HIGH);

        }
    break;

    case GX_SIGNAL(ID_FIVE, GX_EVENT_TOGGLE_OFF):
        {

                   g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_13,IOPORT_LEVEL_LOW);

        }
        break;
    case GX_SIGNAL(ID_OFF, GX_EVENT_TOGGLE_OFF):
        {
        g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_07,IOPORT_LEVEL_LOW);
        g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_06,IOPORT_LEVEL_LOW);
        g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07,IOPORT_LEVEL_LOW);
        g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_14,IOPORT_LEVEL_LOW);
        g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_13,IOPORT_LEVEL_LOW);

        }
    break;
    case GX_SIGNAL(ID_OFF, GX_EVENT_TOGGLE_ON):
        {
        g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_07,IOPORT_LEVEL_HIGH);
        g_ioport.p_api->pinWrite(IOPORT_PORT_05_PIN_06,IOPORT_LEVEL_HIGH);
        g_ioport.p_api->pinWrite(IOPORT_PORT_01_PIN_07,IOPORT_LEVEL_HIGH);
        g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_14,IOPORT_LEVEL_HIGH);
        g_ioport.p_api->pinWrite(IOPORT_PORT_06_PIN_13,IOPORT_LEVEL_HIGH);

        }





    default:
        return gx_window_event_process(widget, event_ptr);
    }
    return 0;
}


Conclusion
This was a great project to learn about memory allocation and how to integrated the LCD and the Hardware. The LCD can be used to control practically any application. The best learning experience was during the interaction with Renesas, and the high level of support that Renesas was able to provide when I ran into trouble or had any questions. The Renesas Team was very professional, extremely knowledgeable and always eager to help.

Robinson Paniagua

@jcasman @craig … Thanks for the new board !! (SA37). I will be posting projects based on that board soon.


SK-S7G2 Tutorials
#2

This is such an awesome project and I’m sure it will inspire other people to build a great interface. Thank you for this contribution.

When you said, “Renesas Tech Team,” did you start off the communication with this link?

I was just wondering the best way for people in this community to get technical help from Renesas.

Man, you’re really learning quickly. It’s great to see the evolution of your projects.

Have you thought about diving into the IoT cloud portions as well, either with the SK-S7G2 or the S3A7?

SK-S7G2 Connected Weather Quick Start

S3A7 with Smart Garage Monitoring Demo

Seems like you’re going to master the touchscreen and I/O soon and may want to branch into sensor data analytics and workflow with mobile or email reports.


#3

Craig,

That’s exactly where I started my communications. This is probably my last on the LCD and output. I was definitely thinking about learning how to read sensor data and the UART features of the board, this is my next area of interest. I like to get a good handle on things before I attempt to move on to the next topic. Getting a gauge to rotate was a big itch which I had to scratch, it took some extensive hours, which turned into days to finally figure it out. lol. Sensors and UART is definitely next for me. I also need to look at the IOT cloud. I have no idea about the IOT cloud and its capabilities.

Robinson Paniagua


#4

That gauge is really awesome. Looks so professional. Thanks for making that available.

As you also have the S3A7 IoT Fast Prototyping Kit, I think a good tutorial is the S3A7 With Smart Garage Monitoring Demo. You can fairly quickly get sensor data back. It’s a little tricky due to the WiFi and some problems with the initial WiFi connection. Once you get the initial configuration going, then it works smoothly.

If you have any problems with setup, go to the Hello Cloud Lab with Renesas IoT Sandbox and Synergy S3A7 IoT Fast Prototyping Kit.


#5

Hi Robin

I am also in the same process just like you. I already know some base about Renesas IOT but learning about getting sensor data using e2 studio is major important steps. Sending values to IOT and whole punch of backend steps in IOT can be. ext step.

Please share your finding how to get sensor values.

I went thru sensors datasheet and what need to do get value using I2C protocol. But without s7g2 board details and configration details its hard to figure out.

If there is simple tutorial how to interact with any I2C suppprted device from renesas e2studio (adding driver, framework, configuration like channels, thread priority etc would be greatly helpfull, we can easily learn and do other sensor value to main application.

There are examples to import and see sensor value but I strongly beleive in learning steps by step instead magic blackbox projects. Those pre built projects often diffrent board or SSP version and latest SSP1.2.0 many yhings moved and changed compare to example projects documents. I think learning under current release would be better.

Renesas built great tools to put things together but different version and constant changes make little harder to find details.

thnaks to IOT community


#6

For the SK-S7G2, the AMS and Connected Weather Demo will guide you through using SPI Driver on r_rspi. Note that there are several tutorials with similar names with Weather. The one that shows SPI uses the AMS Sensor.

If you do not have an AMS Sensor, you can probably get one from @jcasman if you’re willing to write up your experiences connecting the AMS Sensor to the SK-S7G2.

Also, I did go through the S3A7 Tutorial with Sensiron Grove Sensor and got it to work.


#7

@elpaniagua Renesas America just Tweeted out your tutorial. You’re getting some good visibility. Keep up the good work!