This post is part of my Roadtest Review of Cypress PSoC 62S2 Wi-Fi & BT5.0 Pioneer Dev Kit - Review. My review is splitted into multiple reviews and tutorials. Main page of review contains brief description of every chapter. Some projects are implemented in multiple variants. Main page of review contains brief description about every chapter, project and variants and contains some reccomendations for reading.
Table of Contents
- Intruction, Table of Contents, Overview of Table of Contets
- Review of Development Board
- Review of Microcontroller
- Review of Wi-FI and BT Module
- Review of Onboard Peripherals
- Review of Onboard Programmer and Debugger
- Review of Development Software
- Review of Documentation
- Project 1 - Serial Interfaces
- Project done using low level registry accesses
- Project done using PDL library
- Project done using HAL library (this article)
- Project done using MBED
- Project 2 - Simple Cloud Application
- Project 3 - FRAM
- Project 4 - CapSense and Bluetooth
- Project 5 - Dual Core Application
- Project 6 - Profiler
- Summary and Score
Project 1 – Serial Interfaces
Project 1 is simple project in which I connect I2C temperature sensor HTU21D, reads temperature using them and prints it over UART. All articles and variants of this project are available as tutorials. I have used this to make opinions about Cypress platform and I reused these skills later when writing chapters with “Review” in name. This chapter is designed as tutorial, not a review. I have implemented this project in 4 ways:
- In C and ModusToolbox IDE without using any library. Just accessing registers. I have done this to look how are some peripherals of MCU designed. If their design makes sense and If it is easy to use them. It shows how to setup clocks of the MCU, setup I2C, UART and Timer (TCPWM) and communicate over it. All just using raw registry access. For definition of registers, I am including PDL but otherwise solution shown in tutorial does not use any library.
- In C and ModusToolbox IDE using PDL library provided by Cypress. This example features my library from github to control sensor and is based on PDL library provided by Cypress. Otherwise, it does the same as previous two variants, but it is hidden in library calls. This mainly shows how easy is to use library provided by Cypress.
- In C and ModusToolbox IDE using HAL library provided by Cypress. This variant also does the same but uses HAL library provided by Cypress and shows how easy is to use this library.
- In C and MBED Studio. Solution is based on MBED OS. This variant shows portable solution using MBED environment.
This is third variant of first project. This variant shows the most common way how to develop on PSoC 62 platform. There are also lower-level variants of this project. Lastly there are also variant using MBED environment. This variant shows HAL library provided by Cypress. This library enables you to very easily use peripherals of PSoC.
Creating project in ModusToolbox
At the beginning we need to create a new project of template Empty PSoC6 App, add library retarget-io and generate launches using Quick panel. All these steps are described (with images) in the first variant of this project.
Writing code
At the beginning we will initialize MCU (their clocks, power options and such other things) using cybsp_init function and configure redirection of printf function to UART (using retarget-io library). This is done by following code. Add it at the beginning of main.
cy_rslt_t result; result = cybsp_init(); if (result != CY_RSLT_SUCCESS) { CY_ASSERT(0); } result = cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, 115200); if (result != CY_RSLT_SUCCESS) { CY_ASSERT(0); }
Then we will initialize I2C but we must know which pins to use.
Selecting correct I2C pins
In the project I will use the HTU21DHTU21D which will be attached to the board using expansion port. I will use P9_1 as SDA and P9_0 as SCL. This choice is not random. Selected ports must have support for I2C which means that there must exists at least one Serial Communication Block (SCB) which’s signals can be connected to these ports using High Speed Input Output Matrix (HSIOM). These mappings are described in the datasheet (not a TRM) because they are device specific (partially they are family specific). In this case on the P9_1 and P9_0 is mapped SCB number 2.
I2C Initialization code is following:
result = cyhal_i2c_init(&i2c, P9_1, P9_0, NULL); if (result != CY_RSLT_SUCCESS) { CY_ASSERT(0); }
The first parameter of library is address of structure for holding internal state for HAL. Declare it as global variable.
cyhal_i2c_t i2c;
Code is easy with HAL library. Library will auto detect peripheral number and do all initialization stuff including configuration of clock system. If you want custom clocks, you can provide them using 4th parameter of cyhal_i2c_init function but if you want to automatically assign and configure one, you can pass NULL and library will do it for you automatically.
Last initialization code is for red and green channels of RGB led which I will use to signalize success or failure.
// configure port to red channel of RGB led result = cyhal_gpio_init(P1_1, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, 1); if (result != CY_RSLT_SUCCESS) { CY_ASSERT(0); } // configure port to green channel of RGB led result = cyhal_gpio_init(P0_5, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, 1); if (result != CY_RSLT_SUCCESS) { CY_ASSERT(0); }
Now we can easily create infinite loop with code.
while (1) { }
Now we will make function for reading temperature over I2C. It will return 0 on success, otherwise non-zero and measured temperature return using pointer parameter.
int ReadTemperature(float* temperature) { }
At the beginning we will declare variable for storing status of HAL calls, and two buffers which we will transfer to and from the sensor. Command is single byte buffer so I will define it as simple variable.
cy_rslt_t result; uint8_t command = 0xE3; uint8_t receiveBuffer[3];
Now let’s write function which will read temperature using sensor. The function will do following I2C operations:
- Start
- Address (0x40 << 1) + Write (0)
- Write command 0xE3
- Repeated start
- Address (0x40 << 1) + Read (1)
- Read 3 bytes (2 bytes are encoded temperature and third is CRC)
- Stop
HAL library has functions cyhal_i2c_master_write and cyhal_i2c_master_read to do transfers. This functions automatically generates start or repeated start, send address (second parameter) and direction bit and transfer buffer (third parameter) of specified length (fourth parameter). Both functions support timeout (fifth parameter) and you can specify if you want complete transfer by generating stop sequence or want to hold line low (sixth parameter). In first transfer we do not send stop and in the second we do. Code is following:
result = cyhal_i2c_master_write(&i2c, 0x40, &command, 1, 1000, 0); if (result != CY_RSLT_SUCCESS) { return 1; } result = cyhal_i2c_master_read(&i2c, 0x40, receiveBuffer, 3, 1000, 1); if (result != CY_RSLT_SUCCESS) { return 1; }
Now we will check CRC of received message and parse temperature to float. I will use functions HTU21D_ParseTemperature and HTU21D_VerifyChecksum from my library available at GitHub. Copy them from https://github.com/misaz/HTU21DLibrary/blob/master/src/HTU21D.c and remove underscore from their name. Functions returns constants defined in HTU21D.h. Insert them at the beginning of your source code.
#define HTU21D_E_OK 0 #define HTU21D_E_TIMEOUT -1 #define HTU21D_E_ADDR_NACKED -2 #define HTU21D_E_BUS_ERROR -3 #define HTU21D_E_BAD_CRC -4
Now we can complete our ReadTemperature function by calling HTU21D_VerifyChecksum, HTU21D_ParseTemperature and returning zero status in case of success.
if (HTU21D_VerifyChecksum((uint8_t*)receiveBuffer)) { return 1; } HTU21D_ParseTemperature(temperature, receiveBuffer); return 0;
Go back to main. We will write logic of infinite loop. In infinite loop we must try read temperature. In case of success print it and in case of failure print error message. Because we initialized retarget-io library we can use printf. We will also set LEDs to visualize success or error. At last, we will wait for some time using HAL delay function.
float temperature; if (ReadTemperature(&temperature) == 0) { cyhal_gpio_write(P1_1, 1); cyhal_gpio_write(P0_5, 0); printf("Temperature is %.2f°C\r\n", temperature); } else { cyhal_gpio_write(P1_1, 0); cyhal_gpio_write(P0_5, 1); printf("Error while reading temperature.\r\n"); } cyhal_system_delay_ms(100);
Testing
Now you can run the program using run or debug button in quick panel and as result you will see measured temperature on the UART serial monitor.