2021-05-23 19:06:17 -04:00
/*
* SPDX - FileCopyrightText : 2021 Espressif Systems ( Shanghai ) CO LTD
*
* SPDX - License - Identifier : Apache - 2.0
*/
2020-05-11 07:50:17 -04:00
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
# include "freertos/semphr.h"
# include "unity.h"
# include "test_utils.h"
# include "esp_rom_sys.h"
# include "soc/soc_caps.h"
# include "hal/cpu_ll.h"
# include "driver/gpio.h"
# if SOC_DEDICATED_GPIO_SUPPORTED
# include "driver/dedic_gpio.h"
TEST_CASE ( " Dedicated GPIO bundle install/uninstall " , " [dedic_gpio] " )
{
const int test_gpios [ SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2 ] = { 0 } ;
const int test2_gpios [ SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2 + 1 ] = { 0 } ;
const int test3_gpios [ SOC_DEDIC_GPIO_OUT_CHANNELS_NUM + 1 ] = { 0 } ;
dedic_gpio_bundle_handle_t test_bundle , test_bundle2 , test_bundle3 = NULL ;
dedic_gpio_bundle_config_t bundle_config = {
. gpio_array = test_gpios ,
. array_size = sizeof ( test_gpios ) / sizeof ( test_gpios [ 0 ] ) ,
} ;
dedic_gpio_bundle_config_t bundle_config2 = {
. gpio_array = test2_gpios ,
. array_size = sizeof ( test2_gpios ) / sizeof ( test2_gpios [ 0 ] ) ,
. flags = {
. out_en = 1 ,
} ,
} ;
dedic_gpio_bundle_config_t bundle_config3 = {
. gpio_array = test3_gpios ,
. array_size = sizeof ( test3_gpios ) / sizeof ( test3_gpios [ 0 ] ) ,
. flags = {
. out_en = 1 ,
} ,
} ;
TEST_ASSERT_EQUAL_MESSAGE ( ESP_ERR_INVALID_ARG , dedic_gpio_new_bundle ( & bundle_config , & test_bundle ) , " shouldn't create bundle if no mode is specified " ) ;
bundle_config . flags . out_en = 1 ;
TEST_ASSERT_EQUAL_MESSAGE ( ESP_OK , dedic_gpio_new_bundle ( & bundle_config , & test_bundle ) , " create bundle with half channels failed " ) ;
uint32_t mask = 0 ;
TEST_ESP_OK ( dedic_gpio_get_out_mask ( test_bundle , & mask ) ) ;
TEST_ASSERT_EQUAL_MESSAGE ( ( 1 < < ( SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2 ) ) - 1 , mask , " wrong out mask " ) ;
TEST_ESP_OK ( dedic_gpio_get_in_mask ( test_bundle , & mask ) ) ;
TEST_ASSERT_EQUAL_MESSAGE ( 0 , mask , " wrong in mask " ) ;
TEST_ASSERT_EQUAL_MESSAGE ( ESP_ERR_NOT_FOUND , dedic_gpio_new_bundle ( & bundle_config2 , & test_bundle2 ) , " shouldn't create bundle if there's no enough channels " ) ;
TEST_ASSERT_EQUAL_MESSAGE ( ESP_OK , dedic_gpio_del_bundle ( test_bundle ) , " delete bundle failed " ) ;
TEST_ASSERT_EQUAL_MESSAGE ( ESP_ERR_INVALID_ARG , dedic_gpio_new_bundle ( & bundle_config3 , & test_bundle3 ) , " shouldn't create bundle if the array size exceeds maximum " ) ;
}
# define TEST_GPIO_GROUP_SIZE (4)
typedef struct {
SemaphoreHandle_t sem ;
const int gpios [ TEST_GPIO_GROUP_SIZE ] ;
} test_dedic_task_context_t ;
static void test_dedic_gpio_on_specific_core ( void * args )
{
test_dedic_task_context_t * ctx = ( test_dedic_task_context_t * ) args ;
uint32_t value = 0 ;
cpu_ll_write_dedic_gpio_all ( 0x0 ) ; // clear all out channels
// configure a group of GPIOs, output only
const int bundleA_gpios [ ] = { ctx - > gpios [ 0 ] , ctx - > gpios [ 1 ] } ;
gpio_config_t io_conf = {
. mode = GPIO_MODE_OUTPUT ,
} ;
for ( int i = 0 ; i < sizeof ( bundleA_gpios ) / sizeof ( bundleA_gpios [ 0 ] ) ; i + + ) {
io_conf . pin_bit_mask = 1ULL < < bundleA_gpios [ i ] ;
gpio_config ( & io_conf ) ;
}
// Create bundleA, output only
dedic_gpio_bundle_handle_t bundleA = NULL ;
dedic_gpio_bundle_config_t bundleA_config = {
. gpio_array = bundleA_gpios ,
. array_size = sizeof ( bundleA_gpios ) / sizeof ( bundleA_gpios [ 0 ] ) ,
. flags = {
. out_en = 1 ,
} ,
} ;
TEST_ESP_OK ( dedic_gpio_new_bundle ( & bundleA_config , & bundleA ) ) ;
// configure another group of GPIOs, input and output
const int bundleB_gpios [ ] = { ctx - > gpios [ 2 ] , ctx - > gpios [ 3 ] } ;
io_conf . mode = GPIO_MODE_INPUT_OUTPUT ;
for ( int i = 0 ; i < sizeof ( bundleB_gpios ) / sizeof ( bundleB_gpios [ 0 ] ) ; i + + ) {
io_conf . pin_bit_mask = 1ULL < < bundleB_gpios [ i ] ;
gpio_config ( & io_conf ) ;
}
// GPIO bundleB, input and output
dedic_gpio_bundle_handle_t bundleB = NULL ;
dedic_gpio_bundle_config_t bundleB_config = {
. gpio_array = bundleB_gpios ,
. array_size = sizeof ( bundleB_gpios ) / sizeof ( bundleB_gpios [ 0 ] ) ,
. flags = {
. in_en = 1 ,
. out_en = 1 ,
} ,
} ;
TEST_ESP_OK ( dedic_gpio_new_bundle ( & bundleB_config , & bundleB ) ) ;
dedic_gpio_bundle_write ( bundleA , 0x01 , 0x01 ) ;
dedic_gpio_bundle_write ( bundleB , 0x03 , 0x03 ) ;
value = cpu_ll_read_dedic_gpio_out ( ) ;
TEST_ASSERT_EQUAL ( 0x0D , value ) ; // 1101
value = cpu_ll_read_dedic_gpio_in ( ) ;
TEST_ASSERT_EQUAL ( 0x03 , value ) ; // 11
dedic_gpio_bundle_write ( bundleB , 0x02 , 0x0 ) ;
value = cpu_ll_read_dedic_gpio_out ( ) ;
TEST_ASSERT_EQUAL ( 0x05 , value ) ; // 0101
value = cpu_ll_read_dedic_gpio_in ( ) ;
TEST_ASSERT_EQUAL ( 0x01 , value ) ; // 01
cpu_ll_write_dedic_gpio_all ( 0x0F ) ; // Set all out channels
value = cpu_ll_read_dedic_gpio_out ( ) ;
TEST_ASSERT_EQUAL ( 0x0F , value ) ;
value = cpu_ll_read_dedic_gpio_in ( ) ;
TEST_ASSERT_EQUAL ( 0x03 , value ) ; // 11
TEST_ASSERT_EQUAL ( 0x03 , dedic_gpio_bundle_read_out ( bundleA ) ) ; // 11
TEST_ASSERT_EQUAL ( 0x00 , dedic_gpio_bundle_read_in ( bundleA ) ) ; // input is not enabled for bundleA
TEST_ASSERT_EQUAL ( 0x03 , dedic_gpio_bundle_read_out ( bundleB ) ) ; // 11
TEST_ASSERT_EQUAL ( 0x03 , dedic_gpio_bundle_read_in ( bundleB ) ) ; // 11
TEST_ESP_OK ( dedic_gpio_del_bundle ( bundleA ) ) ;
TEST_ESP_OK ( dedic_gpio_del_bundle ( bundleB ) ) ;
xSemaphoreGive ( ctx - > sem ) ;
vTaskDelete ( NULL ) ;
}
TEST_CASE ( " Dedicated GPIO run on multiple CPU core " , " [dedic_gpio] " )
{
SemaphoreHandle_t sem = xSemaphoreCreateCounting ( SOC_CPU_CORES_NUM , 0 ) ;
for ( int i = 0 ; i < SOC_CPU_CORES_NUM ; i + + ) {
int start_gpio = i * TEST_GPIO_GROUP_SIZE ;
test_dedic_task_context_t isr_ctx = {
. sem = sem ,
. gpios = { start_gpio , start_gpio + 1 , start_gpio + 2 , start_gpio + 3 }
} ;
xTaskCreatePinnedToCore ( test_dedic_gpio_on_specific_core , " dedic_gpio_test_tsk " , 4096 , & isr_ctx , 1 , NULL , i ) ;
}
for ( int i = 0 ; i < SOC_CPU_CORES_NUM ; i + + ) {
xSemaphoreTake ( sem , pdMS_TO_TICKS ( 1000 ) ) ;
}
vSemaphoreDelete ( sem ) ;
}
IRAM_ATTR static void test_dedic_gpio_isr_callback ( void * args )
{
SemaphoreHandle_t sem = ( SemaphoreHandle_t ) args ;
BaseType_t high_task_wakeup = pdFALSE ;
esp_rom_printf ( " GPIO event \r \n " ) ;
xSemaphoreGiveFromISR ( sem , & high_task_wakeup ) ;
if ( high_task_wakeup ) {
esp_rom_printf ( " high priority task wake up \r \n " ) ;
}
}
TEST_CASE ( " Dedicated GPIO interrupt and callback " , " [dedic_gpio] " )
{
SemaphoreHandle_t sem = xSemaphoreCreateBinary ( ) ;
// configure GPIO
const int bundle_gpios [ ] = { 0 , 1 } ;
gpio_config_t io_conf = {
. mode = GPIO_MODE_INPUT_OUTPUT ,
} ;
for ( int i = 0 ; i < sizeof ( bundle_gpios ) / sizeof ( bundle_gpios [ 0 ] ) ; i + + ) {
io_conf . pin_bit_mask = 1ULL < < bundle_gpios [ i ] ;
gpio_config ( & io_conf ) ;
}
dedic_gpio_bundle_handle_t bundle = NULL ;
dedic_gpio_bundle_config_t bundle_config = {
. gpio_array = bundle_gpios ,
. array_size = sizeof ( bundle_gpios ) / sizeof ( bundle_gpios [ 0 ] ) ,
. flags = {
. in_en = 1 ,
. out_en = 1 ,
} ,
} ;
TEST_ESP_OK ( dedic_gpio_new_bundle ( & bundle_config , & bundle ) ) ;
// enable interrupt on GPIO1
TEST_ESP_OK ( gpio_set_intr_type ( 1 , GPIO_INTR_POSEDGE ) ) ;
// install gpio isr service
TEST_ESP_OK ( gpio_install_isr_service ( 0 ) ) ;
// hook isr handler for specific gpio pin
TEST_ESP_OK ( gpio_isr_handler_add ( 1 , test_dedic_gpio_isr_callback , sem ) ) ;
// trigger a posedge on GPIO1
dedic_gpio_bundle_write ( bundle , BIT ( 1 ) , 0x00 ) ;
dedic_gpio_bundle_write ( bundle , BIT ( 1 ) , 0xFF ) ;
// wait for done semaphore
TEST_ASSERT_EQUAL ( pdTRUE , xSemaphoreTake ( sem , pdMS_TO_TICKS ( 1000 ) ) ) ;
// remove isr handler for gpio number
TEST_ESP_OK ( gpio_isr_handler_remove ( 1 ) ) ;
// uninstall GPIO interrupt service
gpio_uninstall_isr_service ( ) ;
TEST_ESP_OK ( dedic_gpio_del_bundle ( bundle ) ) ;
vSemaphoreDelete ( sem ) ;
}
# endif // #if SOC_DEDICATED_GPIO_SUPPORTED