Blinky - owntech-foundation/Tutorials GitHub Wiki

Objectives

The goal of this tutorial is to understand the architecture of the code in your main.cpp file and to use the microcontroller for the first time. For that, you will turn ON and OFF the embedded LED of the SPIN. The previous tutorial need to be completed.

Required hardware

* TWIST and/or SPIN
* PC 64-bits (windows or linux)

Required software

* Git
* Visual Studio Code with PlatformIO [Check our previous tutorial](Twist-tutorial-Setting-up-your-environment)

Understand your work environment

You will work on a simplified work environment as shown by the image below:

Work Environment

You will interact with two different files:

  • main.cpp : contains all of the executable code. You will update this file throughout the tutorials.
  • platformio.ini : contains all the setup for the platformio project. You will interact with this file only a few times.

Understand the software architecture

Inside the SPIN board that you are using, there is a digital stack. This digital stack is divided into several blocks. Each block has its own different execution time as represented in the figure below.

SPIN-digital-stack

On the bottom you have the power hardware, that handle the power flows.

The hardware peripherals are peripherals of the micro-controller that are set and run on their own. These are simplified to :

  • PWM Generator : A peripheral that generates ON/OFF pulses. In our application they have a frequency of 200kHz and a variable duty cycle. The duty cycle is the time the pulse is on. We will come back to this later, in the Control your power with PWM tutorial.
  • ADC : A peripheral that converts the physical sensor signals from the power converter into digital data. They are synchronized with the PWM and allow for very high-precision measurements. We will get more information on them in the Activate measurements tutorial.

On the top these peripherals runs the software block, which is the code executed by the main.cpp file. It is composed of two types of tasks:

  • Critital task: This task is synchronized with the PWM signals. You can have only one critical task. It is in this task that the input setpoint is sent, the data is acquired, the acquired values are saved and the control is calculated.
  • Background tasks: This task is asynchronous and happens whenever the micro-controller has enough time to work. In practice, you can have multiple background tasks handling anything from state machines to communication tasks with the outside. In our example we will have one background task operating on the scale of a hundred miliseconds.

For this example, we won't use the critical task, as we won't use the power features yet.

Modify the code

  1. Define the variables and add definitions

In the beginning of the code, add support for the console

#include "zephyr/console/console.h"

In src/main.cpp, in the section USER VARIABLE DECLARATIONS declare a new enum for the operation modes.

enum serial_interface_menu_mode //LIST OF POSSIBLE MODES FOR THE OWNTECH CONVERTER
{
    IDLEMODE =0,
    SERIALMODE
};

serial_interface_menu_mode mode = IDLEMODE; 
uint8_t received_serial_char;

In the LOOP FUNCTIONS DECLARATION add the application task

//--------------LOOP FUNCTIONS DECLARATION--------------------
// do not erase the previous tasks!!!!
void loop_application_task();   // Code to be executed in the background task
void loop_communication_task();   // Code to be executed in the background task
  1. Configure the hardware peripherals

In src/main.cpp, in the function setup_routine(), check that :

  • We load the version of the SPIN using the spin.version.setBoardVersion(SPIN_v_1_0) function, use SPIN_v_1_0 by default
  • The console is activated for exchanging messages via serial with the console_init() function.
  • That there the two background tasks communication and application are initialized
void setup_routine()
{
    console_init();

    // Setup the hardware first
    spin.version.setBoardVersion(SPIN_v_1_0);

    // Then declare tasks
    uint32_t app_task_number = task.createBackground(loop_application_task);
    uint32_t comm_task_number = task.createBackground(loop_communication_task);
    //task.createCritical(loop_critical_task, 500); // Uncomment if you use the critical task

    // Finally, start tasks
    task.startBackground(app_task_number);
    task.startBackground(comm_task_number);
    //task.startCritical(); // Uncomment if you use the critical task
}
  1. Loop communication task

In the communication task, we implement a communication loop function that will treat the characters it receives via the serial port. Each character will be associated with a different mode.

In src/main.cpp, in the LOOP FUNCTIONS section, add the following code. This code listens to the serial port and performs an action depending on the character it has received. The character h displays the help menu. The character i switches to IDLEMODE. The character s switches to SERIALMODE. It will allow you to change the duty cycle manually.

//--------------LOOP FUNCTIONS--------------------------------
// Add your communication task just below loop functions
void loop_communication_task()
{
    received_serial_char = console_getchar();
    switch (received_serial_char) {
        case 'h':
            //----------SERIAL INTERFACE MENU-----------------------
            printk(" _____________________________________\n");
            printk("|     ------- MENU ---------          |\n");
            printk("|     press i : idle mode             |\n");
            printk("|     press s : serial mode           |\n");
            printk("|_____________________________________|\n\n");
            //------------------------------------------------------
            break;
        case 'i':
            printk("idle mode\n");
            mode = IDLEMODE;
            break;
        case 's':
            printk("serial mode\n");
            mode = SERIALMODE;
            break;
        default:
            break;
    }
}
  1. Loop application task

Let's create an application task that turns the LED1 ON or OFF depending on the mode. In src/main.cpp, in the function loop_application_task(), add the following code.

void loop_application_task()
{
    if(mode==IDLEMODE) {
        spin.led.turnOff();

    }else if(mode==SERIALMODE) {
        spin.led.turnOn();
    }        
    task.suspendBackgroundMs(100); 
}
  1. Loop critical task

In src/main.cpp, in the loop_critical_task() function, do not modify anything. This control task will remain empty for this tutorial.

  1. Connect hardware (see environment tutorial)
  • Connect the USB power supply cable. The LED2 of the SPIN should be ON.

twist_board_USB_connexion

  1. Build and Upload (build_icon+ flash_icon).
  2. In the bottom toolbar, click on the Serial Monitor icon serial_icon. Select it and press the h key.

Expected outputs

  • Press the h key to display the help menu.
  • Press the s key to switch to SERIALMODE and turn the LED1 ON.
  • Press the i key to switch to IDLEMODE and turn the LED1 OFF.

That’s it!

Contributors

  • 2024.02.25: Luiz Villa, Ayoub Farah
  • 2021.11.04: Romain Delpoux, Loïc Quéval, Adrien Prévost
  • 2021.11.07: Luiz Villa, Antoine Boche
  • 2022.01.24: Luiz Villa, Adrien Prevost, Loïc Quéval
  • 2022.02.01: Luiz Villa, Clement Foucher
  • 2022.02.22: Luiz Villa
  • 2022.03.13: Luiz Villa
  • 2022.06.23: Loïc Quéval
  • 2023.01.14: Luiz Villa
  • 2023.07.10: Luiz Villa
  • 2023.10.01: Mathilde Longuet
  • 2023.10.18: Luiz Villa
  • 2023.11.27: Mathilde Longuet