Skip navigation
Home > All Places > Topics > Cypress Community Blogs > ModusToolbox Blog > Blog > Authors RakshithM_16

ModusToolbox Blog

3 Posts authored by: RakshithM_16 Moderator

In this blog, we will see how we can interface an OLED display with a PSoC 6 device and add it to our application to make a simple standalone system. We developed a ModusToolbox application to interface a DHT-11 sensor with a PSoC 6 device and print the values on a serial terminal application. Printing on a serial terminal implies that the device needs to be always connected to a PC which can be an inconvenience.

If you are new to the blog series, then you can refer to the previous blog here.

 

A quick description on the OLED display before we get started. There are many variations of OLED displays to choose from. I am using an OLED display module containing an SSD1306 controller that is manufactured by Solomon Systech Limited and a 128x64 pixel dot-matrix OLED. This is a monochrome OLED display and can be interfaced using the I2C interface. Additional information about this display can be found here.

 

At this point, you might be expecting me to talk about the driver files needed by the OLED display and how to write low-level I2C interface APIs to interact with the driver files. Now, what if I told you that we have a ready-made board utility library that you can use right off the bat? That’s right! We have one! To add to it, we can now use the emWin library with OLED displays. Isn't that cool!

 

We will start with the application developed in the previous blog. If you do not have the application, you can download it from here. Build and program the application once to confirm that you have the application set up and are ready to begin. To use the OLED display we need to import the libraries and we are going to do just that. Open Library Manager and enable abstraction-rtos (under Abstraction Layers), display-oled-ssd1306 (under Board Utils) and emwin (under PSoC 6 Middleware). After the libraries are imported, open the application makefile, and add EMWIN_OSNTS and FREERTOS to the COMPONENTS variable as shown:

 

COMPONENTS+=EMWIN_OSNTS FREERTOS

 

Just a few more steps, we are almost there. Copy FreeRTOSConfig.h file from <makefile_directory>/libs/freertos/Source/portable directory to <makefile_directory>/source directory. The <makefile_directory> is the directory in which the application makefile exists. The makefile will now consider the copied FreeRTOSConfig.h (in the source directory) and ignore the .h file in the libs directory. Now we need to make the following edits in the FreeRTOSConfig.h file that we copied to the source directory: 

  1. Comment “#warning This is a template” line
  2. Change the values of configUSE_MUTEXES and configUSE_RECURSIVE_MUTEXES macros to 1 like this –

          #define configUSE_MUTEXES                       1

#define configUSE_RECURSIVE_MUTEXES             1

 

All done? Good! We now have the libraries needed for our application set up. Go ahead and build the project to ensure the libraries are set up correctly.

 

Next, create oled_task.h/.c files which will have the OLED Task for our application. The first step is to initialize the display and the libraries. To do that:

  1. Include mtb_ssd1306.h and GUI.h
  2. Initialize I2C peripheral using the I2C HAL Driver
  3. Initialize the OLED display using mtb_ssd1306_init_i2c() API
  4. Finally, initialize the emWin library using GUI_Init() API

If you are stuck or face any issues with the above steps you can refer to the Display OLED SSD1306 Guide. After you are done with these steps, your OLED task should be something similar to this:

You can now use the emWin library APIs in your task to interact with the OLED display. emWin Library has a vast set of features and I will not be covering all the features in this blog post. Refer to the emWin Graphics Library Guide for more information on all the features available. Let me explain what I have done so that you can try and replicate the same.

 

After initialization the OLED task performs the following functions:

  1. Displays the Infineon + Cypress logo
  2. Displays the tagline
  3. In the loop, it continuously updates the humidity and temperature readings

 

Digging into each of these functions in a little more detail:

 

Displaying the logo:

 

Just showing the humidity and temperature will achieve our end goal but to make things a bit more interesting I decided to display the Infineon + Cypress logo and the tagline. This way I get to learn how to display images using emWin! To display an image you will have to first convert the image into a C structure. How do you do that? I will get to this question at the end of this blog. If you know how to do that, great! If not, for now, let's assume we have the structure ready. Once you have the C structure, you first need to set the colour of the image and the background colour and then display the image using the emWin API - GUI_DrawBitmap(). The image needs to stay for a while for us to perceive the image, so a delay is added and then the display is cleared each time using GUI_Clear().

 

Displaying the tagline:

 

This functionality is more straightforward as it is just displaying the text. A few APIs that prove to be useful:

  1. GUI_SetTextMode() – You can use this API to reverse the foreground and background colour, invert the colours, etc.
  2. GUI_SetFont() – Sets the font to be used for text output.
  3. GUI_SetTextAlign() – Sets the alignment for the text in both the X and Y-axis.

Finally, I have used the GUI_DispStringAt() API to display the text at the specified X and Y position (in pixels) respectively on the OLED display.

 

Displaying the sensor readings:

 

Before we get into displaying the sensor readings we will have to consider one more key aspect – how to receive the sensor readings from the DHT task. Previously we had used xQueueReceive() API in the Print task to receive data. We cannot do the same here because the API removes the data from the queue when reading from the queue. So, only one task will receive the data. We can use the xQueuePeek() API which just reads the data from the queue without removing the data. Sounds good? Not really. We now have another problem in our hands. The queue is never cleared so how do we inform the tasks that the elements in the queue are updated? I could think of 2 approaches to tackle this issue:

  1. All tasks except the lowest priority task (Print task in this case) peeks and the lowest priority task clears the queue using the receive API. In this case, we will have to ensure that the Print task is always executed last and it is executed every time the queue is updated without fail. This might cause synchronization issues especially when there are a lot of tasks in the application.
  2. Use FreeRTOS notifications to notify each task that the queue is updated. This works. But we will have to create a new task notification for each new task added to the application which can become a bit messy. On the same lines, we could use an event group to notify each task when the queue is updated and I decided to go with this approach. If you have a better approach to tackle this issue please leave a comment. I would love to know about it and learn.

 

Now that we can get the data from the DHT task we will have to display this data. I have used the same APIs again to display the strings ‘Humidity:’ and ‘Temperature:’. To display the float temperature and humidity values I have used the GUI_DispFloat(). This API also takes in the number of characters to display (including the decimal point) and I have specified 5 characters in this application.

 

That’s pretty much it for the OLED task. Few modifications to the other tasks to incorporate the new developments in the other tasks like the event group etc and you should be good to go! Like before, the entire application is shared on our Community Code Examples Git Repo and you can check it out using this link. Hope you have fun trying it out! To make things a little more interesting, you can try using EInk or TFT displays and experiment with emWin a bit more to customize the application. You can use our code examples as a reference. Created something cool? Feel free to share it with the community  

 

 

 

Now let me get back to the question as promised,

How do I convert an image to a C structure?

 

For this, I used a tool – Segger Bitmap Converter. Download and install the tool. After the tool is set up, click on File > Open and select the image that you want to convert to a C structure. For example, I will select an image of PSoC 6 and the image should open in the tool as shown:

The first thing to do is to reduce the image size to fit the display that you choose. For the OLED display that I am using, I need to reduce it to something less than 128x64. To do this, click on Image > Scale and you can reduce the size in the window that appears:

Next, we will have to make the image monochrome. Click on Image > Conver to > BW

It's ready to be converted to a C structure! Click on File > Save As and give a name to the C file. Next, select 1 bit per pixel in the Format specifications window and click Ok. A .c file will be generated and you will find a similar structure in the file:

You can extern this structure and use it in your application.

There is an entire section dedicated to 2D Graphics in the emWin User Guide and Reference Manual. A lot of fascinating features, do check it out!

 

Welcome to the fifth session of the ModusToolbox Training Series!

 

In the previous session, Session 4: AnyCloud WIFI Design Flow, we learnt about AnyCloud WiFi Design Flow and how to build basic WiFi applications in ModusToolbox using the WiFi Connection Manager Library.

 

In this session, we will learn about the low power modes in PSoC 6 devices - why is low power important? what are the different low power modes available? and how to use these low power modes in your application? We will also go through some of the advanced features of low power in PSoC 6 and a few additional steps that you can inculcate in your application to reduce the current consumption of your device even further.

 

Duration: 60 mins

 

Hardware:

The exercises created as part of this training series have been tested to work on the following board. The exercises might need minor modifications if being used for a different board.

 

Contents:

  1. Introduction to Low Power MCU systems
  2. Overview of different power modes available in PSoC 6
  3. System and CPU power modes
  4. Overview of CPU power modes:
    1. CPU Active
    2. CPU Sleep
    3. CPU Deep Sleep
  5. Description of each system power mode:
    1. System LP
    2. System ULP
    3. System Deep Sleep
    4. System Hibernate
  6. Resources available in each power mode
  7. Wake up sources
  8. Transitioning between low power modes
  9. Power mode transition callbacks
  10. Power reduction techniques
  11. Factors affecting the current measured
  12. Overview of back-up domain resources
  13. References

 

Using the Training Material:

The presentation used in the video is attached to the blog.

 

The training material and exercises are hosted here: ModusToolbox Training Session 5 Github Repository

 

Have any Questions?

Feel free to drop in your queries in the Cypress Developer Community.

In the previous blog, I shared the PSoC Creator projects to interface a PSoC 6 device with the DHT-11 sensor. The previous blog also covered details regarding the DHT-11 sensor and its working. In this blog, we will be creating the project on ModusToolbox 2.1 to achieve the same functionality with a few additional features. You can download ModusToolbox 2.1 here and learn about the new exciting features of ModusToolbox 2.1 release here.

 

We will start by creating an Empty_PSoC6_App. You can create a new project by clicking on New Application in Quick Panel. Select the BSP of your choice. I will be using the CY8CPROTO-062-4343W Kit for this blog. Select the Empty_PSoC6_App, you can rename the project if needed. Click on Create. You can even create the project using the CLI option which you can learn more about here.

 

Now that we have an empty project ready, we need to add the libraries that we will be using for this project. In this project, we will be using the retarget-io and the FreeRTOS middleware libraries. To do that, click on Library Manager under Tools in the Quick Panel and select retarget-io (under Board Utils) and freertos (under PSoC 6 Middleware) as shown. You can now build the project to confirm that there are no errors so far. The ‘project directory’ is now the ‘application directory’. So, in this case, the application directory will be the folder Empty_PSoC6_App or the name of your application in case you have renamed it.

I have predominantly used the code from the Temperature_Sensor_Direct project from my previous blog. The PSoC Creator project was created using PDL. The project would still work if I just copy the entire code and place it in the main.c file. All I have to do is select the right pin in the Device Configurator and name it accordingly. But the problem here is that this makes my project device-dependent. What I mean by this is that if at all I change my device, I will have to reconfigure the pin.  With the release of ModusToolbox 2.0 and 2.1, you would have noticed most of us talk about ‘device agnosticity’. The idea is that the project should work without any changes even when the device is changed. If you are just curious and you want to try out your project on all your devices or if you are as fickle-minded as I am you will soon realize that this is a lifesaver, especially in a project that uses a lot of hardware blocks.

 

To achieve that, I will be using the Hardware Abstraction Layer (HAL) and the Board Support Package (BSP) feature. HAL allows me to easily initialize all my hardware resources in my source code and BSP takes care of the pin allotment of some of the common resources in each device. For example, if I have to use an LED that is on my kit, I can just use the CYBSP_USER_LED macro. This macro is defined specific to each device. Now even if I change my device, I can be assured that I will be using the appropriate LED pin itself. I will be talking in detail about how these features are used in the project when going through each of the source files.

 

In this project, I have also used FreeRTOS to create separate tasks so that each task can just be picked up and used in any FreeRTOS project.

 

To keep the code modular and perspicuous, I have separated the application into three source files –

  • main.c
  • print_task.c
  • dht_task.c

 

main.c file contains the initialization code and the task creation code. You can consider this as the master code and in this file, the FreeRTOS scheduler is started. All the pin/middleware initialization code can be found here. The code first initializes the device and board peripherals and the hardware manager. Next, the retarget-io is initialized. Retarget-io allows you to transmit messages to and from the board via standard printf/scanf functions using a UART SCB block. Just by including cy_retarget_io.h file and initializing the middleware you can use printf and scanf statements directly. So, it saves the time and effort needed to manually map the printf/scanf functions to the UART block. The DATA pin is initialized as shown below –

Each HAL API starts with cyhal followed by the name of the driver and then the functionality. In this case, the API initializes a GPIO pin. The LED is also initialized in a similar way. You can refer to the following link to learn about the different HAL drivers and their usage: HAL Documentation.

The next part is the initialization of FreeRTOS objects. A queue is used for communication of sensor readings between the tasks. The queue-handle is passed as an argument to the tasks. The two tasks, namely, DHT_Task and Print_Task are created with DHT_Task having a higher priority.

 

Moving on to dht_task.c file. As I have mentioned before, this primarily consists of the code used in the Temperature_Sensor_Direct project. I have changed the PDL functions to its HAL counterparts –

  • CY_GPIO_Write()         =>      cyhal_gpio_write()
  • CY_GPIO_Read()         =>     cyhal_gpio_read()
  • CyDelay()                       =>     cyhal_system_delay_ms()
  • CyDelayUs()                  =>      cyhal_system_delay_us()

The task reads the sensor values and if the value is valid, an LED is toggled, and the readings are sent to a queue. If the queue is full, the task will wait until the queue has a vacancy.  Now in case there is a connection failure or the sensor values read are not valid, the error code along with the previous data is sent to the queue. As the sampling rate of the sensor is approximately 2 seconds the task then goes into the blocked state for 2 seconds. After this, the cycle repeats.

 

print_task.c, as the name suggests, contains the Print_Task function. This task has the lowest priority and executes only when all other tasks are in the blocked state. It receives the sensor reading from the queue and prints the value into the serial terminal. If the queue is empty, the task enters the blocked state until DHT_Task sends the reading to the queue.

 

I have attached all the .c/.h files, put in source folder, with this blog. You can go ahead and place this folder in the application directory of the new project that you created and delete the default main.c that was in the project. That’s it! The auto-discovery feature in ModusToolbox will take care of the rest. No more ‘Add to Project’!

 

You can build the project, program the device, and connect the sensor and voila! you now have a simple FreeRTOS project to read the temperature and humidity value using the DHT-11 sensor and print it on a serial terminal. The best part is that it is a ModusToolbox 2.1 project! For your reference, the entire project is shared on our Community Code Examples Git Repo and you can check it out using this link. To know how to import the project, refer to the ReadMe file.

 

Hopefully, by now you will have a basic idea on how to use ModusToolbox 2.1 to develop simple FreeRTOS applications.

 

Here are a couple of things you can do next:

> Try changing the BSP in Library Manager and programming a different device to check out the device-agnostic feature.

> The task is in the blocked state for 2 seconds which means that the PSoC 6 is in the idle state most of the time. You can try exploring the low power capability of PSoC 6. Keep in mind that you should be using the Tickless Idle Mode capability of FreeRTOS for this to work. You can use this code example for reference - CE223508 – PSoC 6 MCU Implementing BLE Multi-connection (4 Slaves)

> You can combine this task with any other FreeRTOS task and create an application. Feel free to post your cool applications and share them with the community!

 

Filter Blog

By date:
By tag: