├── .gitignore ├── CMakeLists.txt ├── FreeRTOS_Kernel_import.cmake ├── LICENSE ├── README.md ├── examples ├── CMakeLists.txt ├── access_all_devices_x2_max_speed │ ├── CMakeLists.txt │ ├── README.md │ └── main.c ├── bme280_max_speed │ ├── CMakeLists.txt │ ├── README.md │ └── main.c ├── common │ ├── CMakeLists.txt │ ├── freertos_hooks.c │ ├── include │ │ ├── FreeRTOSConfig.h │ │ └── mprintf.h │ └── mprintf.c ├── lib │ ├── CMakeLists.txt │ └── UGUI │ │ ├── CMakeLists.txt │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── include │ │ └── ugui.h │ │ ├── ugui.c │ │ └── ugui_config.h ├── mcp9808_basic │ ├── CMakeLists.txt │ ├── README.md │ └── main.c ├── mcp9808_max_speed │ ├── CMakeLists.txt │ ├── README.md │ └── main.c ├── mcp9808_max_speed_sdk_blocking │ ├── CMakeLists.txt │ ├── README.md │ └── main.c ├── mcp9808_minimalistic │ ├── CMakeLists.txt │ ├── README.md │ └── main.c ├── mcp9808_test_all_i2c_functions │ ├── CMakeLists.txt │ ├── README.md │ └── main.c ├── mcp9808_x2_max_speed │ ├── CMakeLists.txt │ ├── README.md │ └── main.c └── ssd1306_bouncing_ball │ ├── CMakeLists.txt │ ├── README.md │ ├── main.c │ └── ugui_config.h ├── notes.txt ├── pico_sdk_import.cmake └── src ├── CMakeLists.txt ├── i2c_dma.c └── include └── i2c_dma.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | set(CMAKE_C_STANDARD 11) 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | include(pico_sdk_import.cmake) 7 | include(FreeRTOS_Kernel_import.cmake) 8 | 9 | project(pico_i2c_dma C CXX ASM) 10 | 11 | pico_sdk_init() 12 | 13 | add_subdirectory("examples") 14 | add_subdirectory("src") 15 | 16 | -------------------------------------------------------------------------------- /FreeRTOS_Kernel_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake 2 | 3 | # This can be dropped into an external project to help locate the FreeRTOS kernel 4 | # It should be include()ed prior to project(). Alternatively this file may 5 | # or the CMakeLists.txt in this directory may be included or added via add_subdirectory 6 | # respectively. 7 | 8 | if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH)) 9 | set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH}) 10 | message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')") 11 | endif () 12 | 13 | set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC/RP2040") 14 | # undo the above 15 | set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..") 16 | 17 | if (NOT FREERTOS_KERNEL_PATH) 18 | # check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly) 19 | get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH) 20 | get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH) 21 | if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH) 22 | get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH) 23 | endif() 24 | if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH) 25 | get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH) 26 | message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake") 27 | elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel") 28 | set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel) 29 | message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}") 30 | endif() 31 | endif () 32 | 33 | if (NOT FREERTOS_KERNEL_PATH) 34 | foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source) 35 | # check if FreeRTOS-Kernel exists under directory that included us 36 | set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) 37 | get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH) 38 | if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt) 39 | get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH) 40 | message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project") 41 | break() 42 | endif() 43 | endforeach() 44 | endif() 45 | 46 | if (NOT FREERTOS_KERNEL_PATH) 47 | message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.") 48 | endif() 49 | 50 | set(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" CACHE PATH "Path to the FreeRTOS Kernel") 51 | 52 | get_filename_component(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 53 | if (NOT EXISTS ${FREERTOS_KERNEL_PATH}) 54 | message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found") 55 | endif() 56 | if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt) 57 | message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain an RP2040 port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}") 58 | endif() 59 | set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE) 60 | 61 | add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Brian Cooke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pico-i2c-dma 2 | A DMA based I2C driver for the RP2040. 3 | 4 | 5 | ## Contents 6 | 7 | - [Installation](#installation) 8 | - [Usage](#usage) 9 | - [Examples](#examples) 10 | - [API](#examples) 11 | 12 | 13 | ## Installation 14 | 15 | #### Prerequisites 16 | 17 | - The [Raspberry Pi Pico SDK](https://github.com/raspberrypi/pico-sdk) has 18 | been successfully installed and the `PICO_SDK_PATH` environment variable has 19 | been appropriately set 20 | - The [FreeRTOS Kernel](https://github.com/FreeRTOS/FreeRTOS-Kernel) has been 21 | successfully installed and the `FREERTOS_KERNEL_PATH` environment variable has 22 | been appropriately set 23 | 24 | If the Prerequisites are satisfied, this repository can be cloned and built 25 | with the following commands: 26 | 27 | ``` 28 | git clone https://github.com/fivdi/pico-i2c-dma.git 29 | cd pico-i2c-dma 30 | mkdir build 31 | cd build 32 | cmake .. 33 | make 34 | ``` 35 | 36 | 37 | ## Usage 38 | 39 | - Call `i2c_dma_init` to initialize an I2C peripheral, its baudrate, its SDA 40 | pin, its SCL pin, to enable the peripheral, and to prepare it for DMA usage 41 | - Call `i2c_dma_*` functions to communicate with I2C devices on an I2C bus 42 | 43 | Here is a minimalistic example that continuously reads the temperature from an 44 | MCP9808 temperature sensor and prints the temperature. 45 | 46 | ```c 47 | #include "FreeRTOS.h" 48 | #include "task.h" 49 | #include "pico/stdlib.h" 50 | #include "i2c_dma.h" 51 | #include "mprintf.h" 52 | 53 | static const uint8_t MCP9808_ADDR = 0x18; 54 | static const uint8_t MCP9808_TEMP_REG = 0x05; 55 | static const int32_t MCP9808_POWER_UP_DELAY_MS = 300; 56 | 57 | static void mcp9808_task(void *args) { 58 | i2c_dma_t *i2c_dma; 59 | i2c_dma_init(&i2c_dma, i2c0, (1000 * 1000), 4, 5); 60 | 61 | vTaskDelay(pdMS_TO_TICKS(MCP9808_POWER_UP_DELAY_MS)); 62 | 63 | while (true) { 64 | uint16_t raw_temp; 65 | i2c_dma_read_word_swapped( 66 | i2c_dma, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp 67 | ); 68 | 69 | double temp = (raw_temp & 0x0fff) / 16.0 - (raw_temp & 0x1000 ? 256 : 0); 70 | 71 | mprintf("temp: %.4f\n", temp); 72 | 73 | vTaskDelay(pdMS_TO_TICKS(1000)); 74 | } 75 | } 76 | 77 | int main(void) { 78 | stdio_init_all(); 79 | 80 | xTaskCreate( 81 | mcp9808_task, "mcp9808-task", configMINIMAL_STACK_SIZE, 82 | NULL, configMAX_PRIORITIES - 2, NULL 83 | ); 84 | 85 | vTaskStartScheduler(); 86 | } 87 | ``` 88 | 89 | 90 | ## Examples 91 | 92 | Examples can be found in the [examples](examples/) directory. The examples 93 | were implemented to verify that the I2C driver functions as expected rather 94 | than to do anything useful. Each example has a readme explaining its purpose. 95 | 96 | Depending on the example, one or more of the following I2C devices will be 97 | required for the example to function as expected: 98 | 99 | - An MCP9808 temperature sensor at address 0x18 on I2C0 (GP4 and GP5) 100 | - A 128x64 pixel SSD1306 OLED display at address 0x3c on I2C0 (GP4 and GP5) 101 | - An MCP9808 temperature sensor at address 0x18 on I2C1 (GP6 and GP7) 102 | - A BME280 sensor at address 0x76 on I2C1 (GP6 and GP7) 103 | 104 | 105 | ## API 106 | 107 | The API is documented in [i2c_dma.h](src/include/i2c_dma.h) 108 | 109 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(access_all_devices_x2_max_speed) 2 | add_subdirectory(bme280_max_speed) 3 | add_subdirectory(common) 4 | add_subdirectory(lib) 5 | add_subdirectory(mcp9808_basic) 6 | add_subdirectory(mcp9808_max_speed) 7 | add_subdirectory(mcp9808_max_speed_sdk_blocking) 8 | add_subdirectory(mcp9808_minimalistic) 9 | add_subdirectory(mcp9808_test_all_i2c_functions) 10 | add_subdirectory(mcp9808_x2_max_speed) 11 | add_subdirectory(ssd1306_bouncing_ball) 12 | 13 | -------------------------------------------------------------------------------- /examples/access_all_devices_x2_max_speed/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(access_all_devices_x2_max_speed 2 | main.c 3 | ) 4 | 5 | target_link_libraries(access_all_devices_x2_max_speed 6 | FreeRTOS-Kernel 7 | FreeRTOS-Kernel-Heap1 8 | pico_stdlib 9 | i2c_dma 10 | common 11 | ) 12 | 13 | pico_enable_stdio_usb(access_all_devices_x2_max_speed 0) 14 | pico_enable_stdio_uart(access_all_devices_x2_max_speed 1) 15 | 16 | pico_add_extra_outputs(access_all_devices_x2_max_speed) 17 | 18 | -------------------------------------------------------------------------------- /examples/access_all_devices_x2_max_speed/README.md: -------------------------------------------------------------------------------- 1 | # access_all_devices_x2_max_speed 2 | 3 | This example can be regarded as a brute-force reliability test. It runs two 4 | identical tasks, `access_all_devices_task`, both of which access all devices 5 | on I2C0 and I2C1 as fast and as often as possible. The idea is that the 6 | program should be capable of running "forever" without crashing. 7 | 8 | This example assumes the following setup: 9 | 10 | - An MCP9808 temperature sensor at address 0x18 on I2C0 (GP4 and GP5) 11 | - An MCP9808 temperature sensor at address 0x18 on I2C1 (GP6 and GP7) 12 | - A BME280 sensor at address 0x76 on I2C1 (GP6 and GP7) 13 | 14 | -------------------------------------------------------------------------------- /examples/access_all_devices_x2_max_speed/main.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "task.h" 3 | #include "pico/stdlib.h" 4 | #include "i2c_dma.h" 5 | #include "mprintf.h" 6 | 7 | static const uint8_t MCP9808_ADDR = 0x18; 8 | static const uint8_t MCP9808_TEMP_REG = 0x05; 9 | 10 | // After power-up the MCP9808 typically requires 250 ms to perform the first 11 | // conversion at the power-up default resolution. See datasheet. 12 | static const int32_t MCP9808_POWER_UP_DELAY_MS = 300; 13 | 14 | static const uint8_t BME280_ADDR = 0x76; 15 | static const uint8_t BME280_ID_REG = 0xd0; 16 | 17 | static i2c_dma_t *i2c0_dma; 18 | static i2c_dma_t *i2c1_dma; 19 | 20 | static void blink_led_task(void *args) { 21 | (void) args; 22 | 23 | gpio_init(PICO_DEFAULT_LED_PIN); 24 | gpio_set_dir(PICO_DEFAULT_LED_PIN, 1); 25 | gpio_put(PICO_DEFAULT_LED_PIN, !PICO_DEFAULT_LED_PIN_INVERTED); 26 | 27 | while (true) { 28 | gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); 29 | vTaskDelay(pdMS_TO_TICKS(500)); 30 | } 31 | } 32 | 33 | static double mcp9808_raw_temp_to_celsius(uint16_t raw_temp) { 34 | return (raw_temp & 0x0fff) / 16.0 - (raw_temp & 0x1000 ? 256 : 0); 35 | } 36 | 37 | // Note that two instances of this task run concurrently. 38 | static void access_all_devices_task(void *args) { 39 | (void) args; 40 | 41 | vTaskDelay(pdMS_TO_TICKS(MCP9808_POWER_UP_DELAY_MS)); 42 | 43 | for (int err_cnt = 0, i = 0; true; i += 1) { 44 | uint16_t raw_temp0; 45 | const int rc0 = i2c_dma_read_word_swapped( 46 | i2c0_dma, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp0 47 | ); 48 | 49 | uint16_t raw_temp1; 50 | const int rc1 = i2c_dma_read_word_swapped( 51 | i2c1_dma, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp1 52 | ); 53 | 54 | uint8_t id; 55 | const int rc2 = i2c_dma_read_byte( 56 | i2c1_dma, BME280_ADDR, BME280_ID_REG, &id 57 | ); 58 | 59 | if (rc0 != PICO_OK || rc1 != PICO_OK || rc2 != PICO_OK) { 60 | err_cnt += 1; 61 | mprintf( 62 | "access all, " 63 | "error (i: %d, rc0: %d, rc1: %d, rc2: %d, errors: %d)\n", 64 | i, rc0, rc1, rc2, err_cnt 65 | ); 66 | } else if (i % 10000 == 0) { 67 | const double celsius0 = mcp9808_raw_temp_to_celsius(raw_temp0); 68 | const double celsius1 = mcp9808_raw_temp_to_celsius(raw_temp1); 69 | mprintf( 70 | "access all, " 71 | "temp0: %.4f, temp1: %.4f, id: %d (i: %d, errors: %d)\n", 72 | celsius0, celsius1, id, i, err_cnt 73 | ); 74 | } 75 | } 76 | } 77 | 78 | static void waste_time_task(void *args) { 79 | (void) args; 80 | 81 | double billion_iterations = 0; 82 | 83 | while (true) { 84 | for (int j = 0; j != 100 * 1000 * 1000; j += 1) { 85 | __asm__("nop"); 86 | } 87 | 88 | billion_iterations += 0.1; 89 | 90 | mprintf("%.1f billion iterations\n", billion_iterations); 91 | } 92 | } 93 | 94 | int main(void) { 95 | stdio_init_all(); 96 | 97 | int rc = i2c_dma_init(&i2c0_dma, i2c0, (1000 * 1000), 4, 5); 98 | if (rc != PICO_OK) { 99 | mprintf("can't configure I2C0\n"); 100 | return rc; 101 | } 102 | 103 | rc = i2c_dma_init(&i2c1_dma, i2c1, (1000 * 1000), 6, 7); 104 | if (rc != PICO_OK) { 105 | mprintf("can't configure I2C1\n"); 106 | return rc; 107 | } 108 | 109 | xTaskCreate( 110 | blink_led_task, 111 | "blink-led-task", 112 | configMINIMAL_STACK_SIZE, 113 | NULL, 114 | configMAX_PRIORITIES - 2, 115 | NULL 116 | ); 117 | 118 | xTaskCreate( 119 | access_all_devices_task, 120 | "access-all-devices-task-1", 121 | configMINIMAL_STACK_SIZE, 122 | NULL, 123 | configMAX_PRIORITIES - 2, 124 | NULL 125 | ); 126 | 127 | xTaskCreate( 128 | access_all_devices_task, 129 | "access-all-devices-task-2", 130 | configMINIMAL_STACK_SIZE, 131 | NULL, 132 | configMAX_PRIORITIES - 2, 133 | NULL 134 | ); 135 | 136 | xTaskCreate( 137 | waste_time_task, 138 | "waste-time-task", 139 | configMINIMAL_STACK_SIZE, 140 | NULL, 141 | configMAX_PRIORITIES - 4, 142 | NULL 143 | ); 144 | 145 | vTaskStartScheduler(); 146 | } 147 | 148 | -------------------------------------------------------------------------------- /examples/bme280_max_speed/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(bme280_max_speed 2 | main.c 3 | ) 4 | 5 | target_link_libraries(bme280_max_speed 6 | FreeRTOS-Kernel 7 | FreeRTOS-Kernel-Heap1 8 | pico_stdlib 9 | i2c_dma 10 | common 11 | ) 12 | 13 | pico_enable_stdio_usb(bme280_max_speed 0) 14 | pico_enable_stdio_uart(bme280_max_speed 1) 15 | 16 | pico_add_extra_outputs(bme280_max_speed) 17 | 18 | -------------------------------------------------------------------------------- /examples/bme280_max_speed/README.md: -------------------------------------------------------------------------------- 1 | # bme280_max_speed 2 | 3 | The goal of this example is to use DMA based I2C functions to continuously read 4 | the 8-bit ID register on a BME280 sensor in order to determine how often the 5 | ID register can be read per second. 6 | 7 | The BME280 is assumed to be at address 0x76 on I2C1 (GP6 and GP7). 8 | 9 | At a baud rate of 1,000,000 the ID register can be read 1,000,000 times in 10 | approximately 61 seconds or 16393 times per second. 11 | 12 | Because DMA based I2C functions are used, the program does not spend any of 13 | its time polling for the I2C operations to complete which allows other tasks 14 | to be performed at the same time. 15 | 16 | In this program two others tasks are performed at the same time. The first 17 | task, `blink_led_task`, blinks an LED at a frequency of 1Hz. The second task, 18 | `waste_time_task`, increments a counter in an endless loop. 19 | 20 | In the 61 seconds that are required to read the ID register 1,000,000 times, 21 | `waste_time_task` can increment it's counter 1,000,000,000 times. Each 22 | iteration of the endless loop incrementing the counter executes 4 instructions 23 | requiring 5 processor cycles: 24 | 25 | ``` 26 | 100002ee: 46c0 nop ; 1 cycle 27 | 100002f0: 3b01 subs r3, #1 ; 1 cycle 28 | 100002f2: 2b00 cmp r3, #0 ; 1 cycle 29 | 100002f4: d1fb bne.n 100002ee ; 2 cycles 30 | ``` 31 | 32 | This information can be used to calculate approximately how much processor 33 | time DMA based I2C requires. 34 | 35 | Processor cycles per second required by `waste_time_task` to increment its 36 | counter: 37 | 38 | ``` 39 | 1e9 * 5 / 61 = 81967213 40 | ``` 41 | 42 | If the processor is running at 125MHz and we assume that all remaining 43 | processor cycles are used for DMA based I2C, then the number of processor 44 | cycles per second required for DMA based I2C is: 45 | 46 | ``` 47 | 125000000 - 81967213 = 43032787 48 | ``` 49 | 50 | The program spends 65.57% of its time incrementing the counter and 34.43% of 51 | its time reading from the BME280 sensor. 52 | 53 | Typical program output: 54 | 55 | ``` 56 | id: 96 (i: 0, errors: 0) 57 | id: 96 (i: 10000, errors: 0) 58 | id: 96 (i: 20000, errors: 0) 59 | id: 96 (i: 30000, errors: 0) 60 | id: 96 (i: 40000, errors: 0) 61 | id: 96 (i: 50000, errors: 0) 62 | id: 96 (i: 60000, errors: 0) 63 | id: 96 (i: 70000, errors: 0) 64 | id: 96 (i: 80000, errors: 0) 65 | id: 96 (i: 90000, errors: 0) 66 | 0.1 billion iterations 67 | id: 96 (i: 100000, errors: 0) 68 | id: 96 (i: 110000, errors: 0) 69 | id: 96 (i: 120000, errors: 0) 70 | id: 96 (i: 130000, errors: 0) 71 | id: 96 (i: 140000, errors: 0) 72 | id: 96 (i: 150000, errors: 0) 73 | id: 96 (i: 160000, errors: 0) 74 | id: 96 (i: 170000, errors: 0) 75 | id: 96 (i: 180000, errors: 0) 76 | id: 96 (i: 190000, errors: 0) 77 | 0.2 billion iterations 78 | id: 96 (i: 200000, errors: 0) 79 | id: 96 (i: 210000, errors: 0) 80 | id: 96 (i: 220000, errors: 0) 81 | id: 96 (i: 230000, errors: 0) 82 | id: 96 (i: 240000, errors: 0) 83 | id: 96 (i: 250000, errors: 0) 84 | id: 96 (i: 260000, errors: 0) 85 | id: 96 (i: 270000, errors: 0) 86 | id: 96 (i: 280000, errors: 0) 87 | id: 96 (i: 290000, errors: 0) 88 | 0.3 billion iterations 89 | id: 96 (i: 300000, errors: 0) 90 | id: 96 (i: 310000, errors: 0) 91 | id: 96 (i: 320000, errors: 0) 92 | id: 96 (i: 330000, errors: 0) 93 | id: 96 (i: 340000, errors: 0) 94 | id: 96 (i: 350000, errors: 0) 95 | id: 96 (i: 360000, errors: 0) 96 | id: 96 (i: 370000, errors: 0) 97 | id: 96 (i: 380000, errors: 0) 98 | id: 96 (i: 390000, errors: 0) 99 | 0.4 billion iterations 100 | id: 96 (i: 400000, errors: 0) 101 | id: 96 (i: 410000, errors: 0) 102 | id: 96 (i: 420000, errors: 0) 103 | id: 96 (i: 430000, errors: 0) 104 | id: 96 (i: 440000, errors: 0) 105 | id: 96 (i: 450000, errors: 0) 106 | id: 96 (i: 460000, errors: 0) 107 | id: 96 (i: 470000, errors: 0) 108 | id: 96 (i: 480000, errors: 0) 109 | id: 96 (i: 490000, errors: 0) 110 | 0.5 billion iterations 111 | id: 96 (i: 500000, errors: 0) 112 | id: 96 (i: 510000, errors: 0) 113 | id: 96 (i: 520000, errors: 0) 114 | id: 96 (i: 530000, errors: 0) 115 | id: 96 (i: 540000, errors: 0) 116 | id: 96 (i: 550000, errors: 0) 117 | id: 96 (i: 560000, errors: 0) 118 | id: 96 (i: 570000, errors: 0) 119 | id: 96 (i: 580000, errors: 0) 120 | id: 96 (i: 590000, errors: 0) 121 | 0.6 billion iterations 122 | id: 96 (i: 600000, errors: 0) 123 | id: 96 (i: 610000, errors: 0) 124 | id: 96 (i: 620000, errors: 0) 125 | id: 96 (i: 630000, errors: 0) 126 | id: 96 (i: 640000, errors: 0) 127 | id: 96 (i: 650000, errors: 0) 128 | id: 96 (i: 660000, errors: 0) 129 | id: 96 (i: 670000, errors: 0) 130 | id: 96 (i: 680000, errors: 0) 131 | id: 96 (i: 690000, errors: 0) 132 | 0.7 billion iterations 133 | id: 96 (i: 700000, errors: 0) 134 | id: 96 (i: 710000, errors: 0) 135 | id: 96 (i: 720000, errors: 0) 136 | id: 96 (i: 730000, errors: 0) 137 | id: 96 (i: 740000, errors: 0) 138 | id: 96 (i: 750000, errors: 0) 139 | id: 96 (i: 760000, errors: 0) 140 | id: 96 (i: 770000, errors: 0) 141 | id: 96 (i: 780000, errors: 0) 142 | id: 96 (i: 790000, errors: 0) 143 | 0.8 billion iterations 144 | id: 96 (i: 800000, errors: 0) 145 | id: 96 (i: 810000, errors: 0) 146 | id: 96 (i: 820000, errors: 0) 147 | id: 96 (i: 830000, errors: 0) 148 | id: 96 (i: 840000, errors: 0) 149 | id: 96 (i: 850000, errors: 0) 150 | id: 96 (i: 860000, errors: 0) 151 | id: 96 (i: 870000, errors: 0) 152 | id: 96 (i: 880000, errors: 0) 153 | id: 96 (i: 890000, errors: 0) 154 | 0.9 billion iterations 155 | id: 96 (i: 900000, errors: 0) 156 | id: 96 (i: 910000, errors: 0) 157 | id: 96 (i: 920000, errors: 0) 158 | id: 96 (i: 930000, errors: 0) 159 | id: 96 (i: 940000, errors: 0) 160 | id: 96 (i: 950000, errors: 0) 161 | id: 96 (i: 960000, errors: 0) 162 | id: 96 (i: 970000, errors: 0) 163 | id: 96 (i: 980000, errors: 0) 164 | id: 96 (i: 990000, errors: 0) 165 | 1.0 billion iterations 166 | id: 96 (i: 1000000, errors: 0) 167 | id: 96 (i: 1010000, errors: 0) 168 | id: 96 (i: 1020000, errors: 0) 169 | id: 96 (i: 1030000, errors: 0) 170 | id: 96 (i: 1040000, errors: 0) 171 | id: 96 (i: 1050000, errors: 0) 172 | id: 96 (i: 1060000, errors: 0) 173 | id: 96 (i: 1070000, errors: 0) 174 | id: 96 (i: 1080000, errors: 0) 175 | 1.1 billion iterations 176 | id: 96 (i: 1090000, errors: 0) 177 | id: 96 (i: 1100000, errors: 0) 178 | id: 96 (i: 1110000, errors: 0) 179 | ... 180 | ``` 181 | 182 | -------------------------------------------------------------------------------- /examples/bme280_max_speed/main.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "task.h" 3 | #include "pico/stdlib.h" 4 | #include "i2c_dma.h" 5 | #include "mprintf.h" 6 | 7 | static const uint8_t BME280_ADDR = 0x76; 8 | static const uint8_t BME280_ID_REG = 0xd0; 9 | 10 | static void blink_led_task(void *args) { 11 | (void) args; 12 | 13 | gpio_init(PICO_DEFAULT_LED_PIN); 14 | gpio_set_dir(PICO_DEFAULT_LED_PIN, 1); 15 | gpio_put(PICO_DEFAULT_LED_PIN, !PICO_DEFAULT_LED_PIN_INVERTED); 16 | 17 | while (true) { 18 | gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); 19 | vTaskDelay(pdMS_TO_TICKS(500)); 20 | } 21 | } 22 | 23 | static void bme280_task(void *args) { 24 | i2c_dma_t *i2c_dma = (i2c_dma_t *) args; 25 | 26 | for (int err_cnt = 0, i = 0; true; i += 1) { 27 | uint8_t id; 28 | const int rc = i2c_dma_read_byte( 29 | i2c_dma, BME280_ADDR, BME280_ID_REG, &id 30 | ); 31 | 32 | if (rc != PICO_OK) { 33 | err_cnt += 1; 34 | mprintf("error (i: %d, rc: %d, errors: %d)\n", i, rc, err_cnt); 35 | } else if (i % 10000 == 0) { 36 | mprintf("id: %d (i: %d, errors: %d)\n", id, i, err_cnt); 37 | } 38 | } 39 | } 40 | 41 | static void waste_time_task(void *args) { 42 | (void) args; 43 | 44 | double billion_iterations = 0; 45 | 46 | while (true) { 47 | for (int j = 0; j != 100 * 1000 * 1000; j += 1) { 48 | __asm__("nop"); 49 | } 50 | 51 | billion_iterations += 0.1; 52 | 53 | mprintf("%.1f billion iterations\n", billion_iterations); 54 | } 55 | } 56 | 57 | int main(void) { 58 | stdio_init_all(); 59 | 60 | static i2c_dma_t *i2c1_dma; 61 | const int rc = i2c_dma_init(&i2c1_dma, i2c1, (1000 * 1000), 6, 7); 62 | if (rc != PICO_OK) { 63 | mprintf("can't configure I2C1\n"); 64 | return rc; 65 | } 66 | 67 | xTaskCreate( 68 | blink_led_task, 69 | "blink-led-task", 70 | configMINIMAL_STACK_SIZE, 71 | NULL, 72 | configMAX_PRIORITIES - 2, 73 | NULL 74 | ); 75 | 76 | xTaskCreate( 77 | bme280_task, 78 | "bme280-task", 79 | configMINIMAL_STACK_SIZE, 80 | i2c1_dma, 81 | configMAX_PRIORITIES - 2, 82 | NULL 83 | ); 84 | 85 | xTaskCreate( 86 | waste_time_task, 87 | "waste-time-task", 88 | configMINIMAL_STACK_SIZE, 89 | NULL, 90 | configMAX_PRIORITIES - 4, 91 | NULL 92 | ); 93 | 94 | vTaskStartScheduler(); 95 | } 96 | 97 | -------------------------------------------------------------------------------- /examples/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(common INTERFACE) 2 | 3 | target_include_directories(common INTERFACE 4 | ${CMAKE_CURRENT_LIST_DIR}/include 5 | ) 6 | 7 | target_sources(common INTERFACE 8 | ${CMAKE_CURRENT_LIST_DIR}/freertos_hooks.c 9 | ${CMAKE_CURRENT_LIST_DIR}/mprintf.c 10 | ) 11 | 12 | target_link_libraries(common INTERFACE 13 | FreeRTOS-Kernel 14 | FreeRTOS-Kernel-Heap1 15 | pico_stdlib 16 | ) 17 | 18 | -------------------------------------------------------------------------------- /examples/common/freertos_hooks.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "task.h" 3 | 4 | void vApplicationMallocFailedHook(void) { 5 | /* Called if a call to pvPortMalloc() fails because there is insufficient 6 | free memory available in the FreeRTOS heap. pvPortMalloc() is called 7 | internally by FreeRTOS API functions that create tasks, queues, software 8 | timers, and semaphores. The size of the FreeRTOS heap is set by the 9 | configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ 10 | 11 | /* Force an assert. */ 12 | configASSERT((volatile void *) NULL); 13 | } 14 | 15 | void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { 16 | (void) pcTaskName; 17 | (void) pxTask; 18 | 19 | /* Run time stack overflow checking is performed if 20 | configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook 21 | function is called if a stack overflow is detected. */ 22 | 23 | /* Force an assert. */ 24 | configASSERT((volatile void *) NULL); 25 | } 26 | 27 | void vApplicationIdleHook(void) { 28 | volatile size_t xFreeHeapSpace; 29 | 30 | /* This is just a trivial example of an idle hook. It is called on each 31 | cycle of the idle task. It must *NOT* attempt to block. In this case the 32 | idle task just queries the amount of FreeRTOS heap that remains. See the 33 | memory management section on the http://www.FreeRTOS.org web site for memory 34 | management options. If there is a lot of heap memory free then the 35 | configTOTAL_HEAP_SIZE value in FreeRTOSConfig.h can be reduced to free up 36 | RAM. */ 37 | xFreeHeapSpace = xPortGetFreeHeapSize(); 38 | 39 | /* Remove compiler warning about xFreeHeapSpace being set but never used. */ 40 | (void) xFreeHeapSpace; 41 | } 42 | 43 | void vApplicationTickHook(void) { 44 | } 45 | 46 | -------------------------------------------------------------------------------- /examples/common/include/FreeRTOSConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS V202107.00 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | #ifndef FREERTOS_CONFIG_H 29 | #define FREERTOS_CONFIG_H 30 | 31 | /*----------------------------------------------------------- 32 | * Application specific definitions. 33 | * 34 | * These definitions should be adjusted for your particular hardware and 35 | * application requirements. 36 | * 37 | * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE 38 | * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 39 | * 40 | * See http://www.freertos.org/a00110.html 41 | *----------------------------------------------------------*/ 42 | 43 | /* Scheduler Related */ 44 | #define configUSE_PREEMPTION 1 45 | #define configUSE_TICKLESS_IDLE 0 46 | #define configUSE_IDLE_HOOK 0 47 | #define configUSE_TICK_HOOK 1 48 | #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) 49 | #define configMAX_PRIORITIES 32 50 | #define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256 51 | #define configUSE_16_BIT_TICKS 0 52 | 53 | #define configIDLE_SHOULD_YIELD 1 54 | 55 | /* Synchronization Related */ 56 | #define configUSE_MUTEXES 1 57 | #define configUSE_RECURSIVE_MUTEXES 1 58 | #define configUSE_APPLICATION_TASK_TAG 0 59 | #define configUSE_COUNTING_SEMAPHORES 1 60 | #define configQUEUE_REGISTRY_SIZE 8 61 | #define configUSE_QUEUE_SETS 1 62 | #define configUSE_TIME_SLICING 1 63 | #define configUSE_NEWLIB_REENTRANT 0 64 | #define configENABLE_BACKWARD_COMPATIBILITY 0 65 | #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 66 | 67 | /* System */ 68 | #define configSTACK_DEPTH_TYPE uint32_t 69 | #define configMESSAGE_BUFFER_LENGTH_TYPE size_t 70 | 71 | /* Memory allocation related definitions. */ 72 | #define configSUPPORT_STATIC_ALLOCATION 0 73 | #define configSUPPORT_DYNAMIC_ALLOCATION 1 74 | #define configTOTAL_HEAP_SIZE (128*1024) 75 | #define configAPPLICATION_ALLOCATED_HEAP 0 76 | 77 | /* Hook function related definitions. */ 78 | #define configCHECK_FOR_STACK_OVERFLOW 2 79 | #define configUSE_MALLOC_FAILED_HOOK 1 80 | #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 81 | 82 | /* Run time and task stats gathering related definitions. */ 83 | #define configGENERATE_RUN_TIME_STATS 0 84 | #define configUSE_TRACE_FACILITY 1 85 | #define configUSE_STATS_FORMATTING_FUNCTIONS 0 86 | 87 | /* Co-routine related definitions. */ 88 | #define configUSE_CO_ROUTINES 0 89 | #define configMAX_CO_ROUTINE_PRIORITIES 1 90 | 91 | /* Software timer related definitions. */ 92 | #define configUSE_TIMERS 1 93 | #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) 94 | #define configTIMER_QUEUE_LENGTH 10 95 | #define configTIMER_TASK_STACK_DEPTH 1024 96 | 97 | /* Interrupt nesting behaviour configuration. */ 98 | /* 99 | #define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] 100 | #define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application] 101 | #define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application] 102 | */ 103 | 104 | /* SMP port only */ 105 | #define configNUM_CORES 2 106 | #define configTICK_CORE 0 107 | #define configRUN_MULTIPLE_PRIORITIES 0 108 | 109 | /* RP2040 specific */ 110 | #define configSUPPORT_PICO_SYNC_INTEROP 1 111 | #define configSUPPORT_PICO_TIME_INTEROP 1 112 | 113 | #include 114 | /* Define to trap errors during development. */ 115 | #define configASSERT(x) assert(x) 116 | 117 | /* Set the following definitions to 1 to include the API function, or zero 118 | to exclude the API function. */ 119 | #define INCLUDE_vTaskPrioritySet 1 120 | #define INCLUDE_uxTaskPriorityGet 1 121 | #define INCLUDE_vTaskDelete 1 122 | #define INCLUDE_vTaskSuspend 1 123 | #define INCLUDE_vTaskDelayUntil 1 124 | #define INCLUDE_vTaskDelay 1 125 | #define INCLUDE_xTaskGetSchedulerState 1 126 | #define INCLUDE_xTaskGetCurrentTaskHandle 1 127 | #define INCLUDE_uxTaskGetStackHighWaterMark 1 128 | #define INCLUDE_xTaskGetIdleTaskHandle 1 129 | #define INCLUDE_eTaskGetState 1 130 | #define INCLUDE_xTimerPendFunctionCall 1 131 | #define INCLUDE_xTaskAbortDelay 1 132 | #define INCLUDE_xTaskGetHandle 1 133 | #define INCLUDE_xTaskResumeFromISR 1 134 | #define INCLUDE_xQueueGetMutexHolder 1 135 | 136 | /* A header file that defines trace macro can be included here. */ 137 | 138 | #endif /* FREERTOS_CONFIG_H */ 139 | 140 | -------------------------------------------------------------------------------- /examples/common/include/mprintf.h: -------------------------------------------------------------------------------- 1 | #ifndef _MPRINTF_H 2 | #define _MPRINTF_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void mprintf(const char* format, ...); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif 15 | 16 | -------------------------------------------------------------------------------- /examples/common/mprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "FreeRTOS.h" 4 | #include "semphr.h" 5 | 6 | void mprintf(const char* format, ...) { 7 | static bool mutex_initialized = false; 8 | static SemaphoreHandle_t mprintf_mutex; 9 | 10 | if (!mutex_initialized) { 11 | mprintf_mutex = xSemaphoreCreateMutex(); 12 | mutex_initialized = true; 13 | } 14 | 15 | xSemaphoreTake(mprintf_mutex, portMAX_DELAY); 16 | 17 | va_list argptr; 18 | va_start(argptr, format); 19 | vprintf(format, argptr); 20 | va_end(argptr); 21 | 22 | xSemaphoreGive(mprintf_mutex); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /examples/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(UGUI) 2 | 3 | -------------------------------------------------------------------------------- /examples/lib/UGUI/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(ugui INTERFACE) 2 | 3 | target_include_directories(ugui INTERFACE 4 | ${CMAKE_CURRENT_LIST_DIR}/include 5 | ) 6 | 7 | target_sources(ugui INTERFACE 8 | ${CMAKE_CURRENT_LIST_DIR}/ugui.c 9 | ) 10 | 11 | -------------------------------------------------------------------------------- /examples/lib/UGUI/LICENSE.md: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------- */ 2 | /* -- µGUI - Generic GUI module (C)Achim Döbler, 2015 -- */ 3 | /* -------------------------------------------------------------------------------- */ 4 | // µGUI is a generic GUI module for embedded systems. 5 | // This is a free software that is open for education, research and commercial 6 | // developments under license policy of following terms. 7 | // 8 | // Copyright (C) 2015, Achim Döbler, all rights reserved. 9 | // URL: http://www.embeddedlightning.com/ 10 | // 11 | // * The µGUI module is a free software and there is NO WARRANTY. 12 | // * No restriction on use. You can use, modify and redistribute it for 13 | // personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 14 | // * Redistributions of source code must retain the above copyright notice. 15 | // 16 | /* -------------------------------------------------------------------------------- */ 17 | /* -- MY SPECIAL THANKS GO TO -- */ 18 | /* -------------------------------------------------------------------------------- */ 19 | // Andrey Filimonov (-->https://github.com/Sermus) 20 | // for giving valuable suggestions, reporting bugs and adding several new features. 21 | // Andrey also put a lot of work in the implementaion of anti-aliased font support. 22 | // 23 | // Mikhail Podkur (-->https://github.com/MikhailPodkur) 24 | // for adding cyrillic 8x12 font, checkbox feature and RGB565 support. 25 | // 26 | // Gustavo Denardin 27 | // for giving valuable suggestions regarding real-time os support. 28 | // 29 | // Samuel Kleiser 30 | // for reporting bugs and giving examples how to improve µGUI. 31 | /* -------------------------------------------------------------------------------- */ 32 | /* -- REVISION HISTORY -- */ 33 | /* -------------------------------------------------------------------------------- */ 34 | // Dec 20, 2015 V0.31 Checkbox component with all funtions added. 35 | // Cyrillic font 8x12 added. 36 | // RGB565 color schema added. 37 | // Windows components font could be getted from current GUI by default 38 | // Mar 18, 2015 V0.3 Driver support added. 39 | // Window and object support added. 40 | // Touch support added. 41 | // Fixed some minor bugs. 42 | // 43 | // Oct 20, 2014 V0.2 Function UG_DrawRoundFrame() added. 44 | // Function UG_FillRoundFrame() added. 45 | // Function UG_DrawArc() added. 46 | // Fixed some minor bugs. 47 | // 48 | // Oct 11, 2014 V0.1 First release. 49 | /* -------------------------------------------------------------------------------- */ 50 | -------------------------------------------------------------------------------- /examples/lib/UGUI/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | ## What is µGUI? 3 | µGUI is a free and open source graphic library for embedded systems. It is platform-independent 4 | and can be easily ported to almost any microcontroller system. As long as the display is capable 5 | of showing graphics, µGUI is not restricted to a certain display technology. Therefore, display 6 | technologies such as LCD, TFT, E-Paper, LED or OLED are supported. The whole module 7 | consists of three files: **ugui.c**, **ugui.h** and **ugui_config.h**. 8 | 9 | ## µGUI Features 10 | * µGUI supports any color, grayscale or monochrome display 11 | * µGUI supports any display resolution 12 | * µGUI supports multiple different displays 13 | * µGUI supports any touch screen technology (e.g. AR, PCAP) 14 | * µGUI supports windows and objects (e.g. button, textbox) 15 | * µGUI supports platform-specific hardware acceleration 16 | * 16 different fonts available 17 | * cyrillic fonts supported 18 | * TrueType font converter available ([https://github.com/AriZuu](https://github.com/AriZuu)) 19 | * integrated and free scalable system console 20 | * basic geometric functions (e.g. line, circle, frame etc.) 21 | * can be easily ported to almost any microcontroller system 22 | * no risky dynamic memory allocation required 23 | 24 | ## µGUI Requirements 25 | µGUI is platform-independent, so there is no need to use a certain embedded system. In order to 26 | use µGUI, only two requirements are necessary: 27 | * a C-function which is able to control pixels of the target display. 28 | * integer types for the target platform have to be adjusted in ugui_config.h. 29 | -------------------------------------------------------------------------------- /examples/lib/UGUI/include/ugui.h: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------- */ 2 | /* -- µGUI - Generic GUI module (C)Achim Döbler, 2015 -- */ 3 | /* -------------------------------------------------------------------------------- */ 4 | // µGUI is a generic GUI module for embedded systems. 5 | // This is a free software that is open for education, research and commercial 6 | // developments under license policy of following terms. 7 | // 8 | // Copyright (C) 2015, Achim Döbler, all rights reserved. 9 | // URL: http://www.embeddedlightning.com/ 10 | // 11 | // * The µGUI module is a free software and there is NO WARRANTY. 12 | // * No restriction on use. You can use, modify and redistribute it for 13 | // personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 14 | // * Redistributions of source code must retain the above copyright notice. 15 | // 16 | /* -------------------------------------------------------------------------------- */ 17 | #ifndef __UGUI_H 18 | #define __UGUI_H 19 | 20 | #include 21 | #include "ugui_config.h" 22 | 23 | 24 | /* -------------------------------------------------------------------------------- */ 25 | /* -- µGUI FONTS -- */ 26 | /* -- Source: http://www.mikrocontroller.net/user/show/benedikt -- */ 27 | /* -------------------------------------------------------------------------------- */ 28 | typedef enum 29 | { 30 | FONT_TYPE_1BPP, 31 | FONT_TYPE_8BPP 32 | } FONT_TYPE; 33 | 34 | typedef struct 35 | { 36 | unsigned char* p; 37 | FONT_TYPE font_type; 38 | UG_S16 char_width; 39 | UG_S16 char_height; 40 | UG_U16 start_char; 41 | UG_U16 end_char; 42 | UG_U8 *widths; 43 | } UG_FONT; 44 | 45 | #ifdef USE_FONT_4X6 46 | extern const UG_FONT FONT_4X6; 47 | #endif 48 | #ifdef USE_FONT_5X8 49 | extern const UG_FONT FONT_5X8; 50 | #endif 51 | #ifdef USE_FONT_5X12 52 | extern const UG_FONT FONT_5X12; 53 | #endif 54 | #ifdef USE_FONT_6X8 55 | extern const UG_FONT FONT_6X8; 56 | #endif 57 | #ifdef USE_FONT_6X10 58 | extern const UG_FONT FONT_6X10; 59 | #endif 60 | #ifdef USE_FONT_7X12 61 | extern const UG_FONT FONT_7X12; 62 | #endif 63 | #ifdef USE_FONT_8X8 64 | extern const UG_FONT FONT_8X8; 65 | #endif 66 | #ifdef USE_FONT_8X12 67 | extern const UG_FONT FONT_8X12; 68 | #endif 69 | #ifdef USE_FONT_8X12_CYRILLIC 70 | extern const UG_FONT FONT_8X12; 71 | #endif 72 | #ifdef USE_FONT_8X14 73 | extern const UG_FONT FONT_8X14; 74 | #endif 75 | #ifdef USE_FONT_10X16 76 | extern const UG_FONT FONT_10X16; 77 | #endif 78 | #ifdef USE_FONT_12X16 79 | extern const UG_FONT FONT_12X16; 80 | #endif 81 | #ifdef USE_FONT_12X20 82 | extern const UG_FONT FONT_12X20; 83 | #endif 84 | #ifdef USE_FONT_16X26 85 | extern const UG_FONT FONT_16X26; 86 | #endif 87 | #ifdef USE_FONT_22X36 88 | extern const UG_FONT FONT_22X36; 89 | #endif 90 | #ifdef USE_FONT_24X40 91 | extern const UG_FONT FONT_24X40; 92 | #endif 93 | #ifdef USE_FONT_32X53 94 | extern const UG_FONT FONT_32X53; 95 | #endif 96 | 97 | /* -------------------------------------------------------------------------------- */ 98 | /* -- TYPEDEFS -- */ 99 | /* -------------------------------------------------------------------------------- */ 100 | typedef struct S_OBJECT UG_OBJECT; 101 | typedef struct S_WINDOW UG_WINDOW; 102 | typedef UG_S8 UG_RESULT; 103 | #ifdef USE_COLOR_RGB888 104 | typedef UG_U32 UG_COLOR; 105 | #endif 106 | #ifdef USE_COLOR_RGB565 107 | typedef UG_U16 UG_COLOR; 108 | #endif 109 | /* -------------------------------------------------------------------------------- */ 110 | /* -- DEFINES -- */ 111 | /* -------------------------------------------------------------------------------- */ 112 | #ifndef NULL 113 | #define NULL ((void*) 0) 114 | #endif 115 | 116 | /* Alignments */ 117 | #define ALIGN_H_LEFT (1<<0) 118 | #define ALIGN_H_CENTER (1<<1) 119 | #define ALIGN_H_RIGHT (1<<2) 120 | #define ALIGN_V_TOP (1<<3) 121 | #define ALIGN_V_CENTER (1<<4) 122 | #define ALIGN_V_BOTTOM (1<<5) 123 | #define ALIGN_BOTTOM_RIGHT (ALIGN_V_BOTTOM|ALIGN_H_RIGHT) 124 | #define ALIGN_BOTTOM_CENTER (ALIGN_V_BOTTOM|ALIGN_H_CENTER) 125 | #define ALIGN_BOTTOM_LEFT (ALIGN_V_BOTTOM|ALIGN_H_LEFT) 126 | #define ALIGN_CENTER_RIGHT (ALIGN_V_CENTER|ALIGN_H_RIGHT) 127 | #define ALIGN_CENTER (ALIGN_V_CENTER|ALIGN_H_CENTER) 128 | #define ALIGN_CENTER_LEFT (ALIGN_V_CENTER|ALIGN_H_LEFT) 129 | #define ALIGN_TOP_RIGHT (ALIGN_V_TOP|ALIGN_H_RIGHT) 130 | #define ALIGN_TOP_CENTER (ALIGN_V_TOP|ALIGN_H_CENTER) 131 | #define ALIGN_TOP_LEFT (ALIGN_V_TOP|ALIGN_H_LEFT) 132 | 133 | /* Default IDs */ 134 | #define OBJ_ID_0 0 135 | #define OBJ_ID_1 1 136 | #define OBJ_ID_2 2 137 | #define OBJ_ID_3 3 138 | #define OBJ_ID_4 4 139 | #define OBJ_ID_5 5 140 | #define OBJ_ID_6 6 141 | #define OBJ_ID_7 7 142 | #define OBJ_ID_8 8 143 | #define OBJ_ID_9 9 144 | #define OBJ_ID_10 10 145 | #define OBJ_ID_11 11 146 | #define OBJ_ID_12 12 147 | #define OBJ_ID_13 13 148 | #define OBJ_ID_14 14 149 | #define OBJ_ID_15 15 150 | #define OBJ_ID_16 16 151 | #define OBJ_ID_17 17 152 | #define OBJ_ID_18 18 153 | #define OBJ_ID_19 19 154 | 155 | /* -------------------------------------------------------------------------------- */ 156 | /* -- FUNCTION RESULTS -- */ 157 | /* -------------------------------------------------------------------------------- */ 158 | #define UG_RESULT_FAIL -1 159 | #define UG_RESULT_OK 0 160 | 161 | /* -------------------------------------------------------------------------------- */ 162 | /* -- UNIVERSAL STRUCTURES -- */ 163 | /* -------------------------------------------------------------------------------- */ 164 | /* Area structure */ 165 | typedef struct 166 | { 167 | UG_S16 xs; 168 | UG_S16 ys; 169 | UG_S16 xe; 170 | UG_S16 ye; 171 | } UG_AREA; 172 | 173 | /* Text structure */ 174 | typedef struct 175 | { 176 | char* str; 177 | const UG_FONT* font; 178 | UG_AREA a; 179 | UG_COLOR fc; 180 | UG_COLOR bc; 181 | UG_U8 align; 182 | UG_S16 h_space; 183 | UG_S16 v_space; 184 | } UG_TEXT; 185 | 186 | /* -------------------------------------------------------------------------------- */ 187 | /* -- BITMAP -- */ 188 | /* -------------------------------------------------------------------------------- */ 189 | typedef struct 190 | { 191 | void* p; 192 | UG_U16 width; 193 | UG_U16 height; 194 | UG_U8 bpp; 195 | UG_U8 colors; 196 | } UG_BMP; 197 | 198 | #define BMP_BPP_1 (1<<0) 199 | #define BMP_BPP_2 (1<<1) 200 | #define BMP_BPP_4 (1<<2) 201 | #define BMP_BPP_8 (1<<3) 202 | #define BMP_BPP_16 (1<<4) 203 | #define BMP_BPP_32 (1<<5) 204 | #define BMP_RGB888 (1<<0) 205 | #define BMP_RGB565 (1<<1) 206 | #define BMP_RGB555 (1<<2) 207 | 208 | /* -------------------------------------------------------------------------------- */ 209 | /* -- MESSAGE -- */ 210 | /* -------------------------------------------------------------------------------- */ 211 | /* Message structure */ 212 | typedef struct 213 | { 214 | UG_U8 type; 215 | UG_U8 id; 216 | UG_U8 sub_id; 217 | UG_U8 event; 218 | void* src; 219 | } UG_MESSAGE; 220 | 221 | /* Message types */ 222 | #define MSG_TYPE_NONE 0 223 | #define MSG_TYPE_WINDOW 1 224 | #define MSG_TYPE_OBJECT 2 225 | 226 | /* -------------------------------------------------------------------------------- */ 227 | /* -- TOUCH -- */ 228 | /* -------------------------------------------------------------------------------- */ 229 | /* Touch structure */ 230 | typedef struct 231 | { 232 | UG_U8 state; 233 | UG_S16 xp; 234 | UG_S16 yp; 235 | } UG_TOUCH; 236 | 237 | 238 | #define TOUCH_STATE_PRESSED 1 239 | #define TOUCH_STATE_RELEASED 0 240 | 241 | /* -------------------------------------------------------------------------------- */ 242 | /* -- OBJECTS -- */ 243 | /* -------------------------------------------------------------------------------- */ 244 | /* Object structure */ 245 | struct S_OBJECT 246 | { 247 | UG_U8 state; /* object state */ 248 | UG_U8 touch_state; /* object touch state */ 249 | void (*update) (UG_WINDOW*,UG_OBJECT*); /* pointer to object-specific update function */ 250 | UG_AREA a_abs; /* absolute area of the object */ 251 | UG_AREA a_rel; /* relative area of the object */ 252 | UG_U8 type; /* object type */ 253 | UG_U8 id; /* object ID */ 254 | UG_U8 event; /* object-specific events */ 255 | void* data; /* pointer to object-specific data */ 256 | }; 257 | 258 | /* Currently supported objects */ 259 | #define OBJ_TYPE_NONE 0 260 | #define OBJ_TYPE_BUTTON 1 261 | #define OBJ_TYPE_TEXTBOX 2 262 | #define OBJ_TYPE_IMAGE 3 263 | #define OBJ_TYPE_CHECKBOX 4 264 | 265 | /* Standard object events */ 266 | #define OBJ_EVENT_NONE 0 267 | #define OBJ_EVENT_CLICKED 1 268 | #ifdef USE_PRERENDER_EVENT 269 | #define OBJ_EVENT_PRERENDER 2 270 | #endif 271 | #ifdef USE_POSTRENDER_EVENT 272 | #define OBJ_EVENT_POSTRENDER 3 273 | #endif 274 | #define OBJ_EVENT_PRESSED 4 275 | #define OBJ_EVENT_RELEASED 5 276 | 277 | 278 | /* Object states */ 279 | #define OBJ_STATE_FREE (1<<0) 280 | #define OBJ_STATE_VALID (1<<1) 281 | #define OBJ_STATE_BUSY (1<<2) 282 | #define OBJ_STATE_VISIBLE (1<<3) 283 | #define OBJ_STATE_ENABLE (1<<4) 284 | #define OBJ_STATE_UPDATE (1<<5) 285 | #define OBJ_STATE_REDRAW (1<<6) 286 | #define OBJ_STATE_TOUCH_ENABLE (1<<7) 287 | #define OBJ_STATE_INIT (OBJ_STATE_FREE | OBJ_STATE_VALID) 288 | 289 | /* Object touch states */ 290 | #define OBJ_TOUCH_STATE_CHANGED (1<<0) 291 | #define OBJ_TOUCH_STATE_PRESSED_ON_OBJECT (1<<1) 292 | #define OBJ_TOUCH_STATE_PRESSED_OUTSIDE_OBJECT (1<<2) 293 | #define OBJ_TOUCH_STATE_RELEASED_ON_OBJECT (1<<3) 294 | #define OBJ_TOUCH_STATE_RELEASED_OUTSIDE_OBJECT (1<<4) 295 | #define OBJ_TOUCH_STATE_IS_PRESSED_ON_OBJECT (1<<5) 296 | #define OBJ_TOUCH_STATE_IS_PRESSED (1<<6) 297 | #define OBJ_TOUCH_STATE_CLICK_ON_OBJECT (1<<7) 298 | #define OBJ_TOUCH_STATE_INIT 0 299 | 300 | /* -------------------------------------------------------------------------------- */ 301 | /* -- WINDOW -- */ 302 | /* -------------------------------------------------------------------------------- */ 303 | /* Title structure */ 304 | typedef struct 305 | { 306 | char* str; 307 | const UG_FONT* font; 308 | UG_S8 h_space; 309 | UG_S8 v_space; 310 | UG_U8 align; 311 | UG_COLOR fc; 312 | UG_COLOR bc; 313 | UG_COLOR ifc; 314 | UG_COLOR ibc; 315 | UG_U8 height; 316 | } UG_TITLE; 317 | 318 | /* Window structure */ 319 | struct S_WINDOW 320 | { 321 | UG_U8 objcnt; 322 | UG_OBJECT* objlst; 323 | UG_U8 state; 324 | UG_COLOR fc; 325 | UG_COLOR bc; 326 | UG_S16 xs; 327 | UG_S16 ys; 328 | UG_S16 xe; 329 | UG_S16 ye; 330 | UG_U8 style; 331 | UG_TITLE title; 332 | void (*cb)( UG_MESSAGE* ); 333 | }; 334 | 335 | /* Window states */ 336 | #define WND_STATE_FREE (1<<0) 337 | #define WND_STATE_VALID (1<<1) 338 | #define WND_STATE_BUSY (1<<2) 339 | #define WND_STATE_VISIBLE (1<<3) 340 | #define WND_STATE_ENABLE (1<<4) 341 | #define WND_STATE_UPDATE (1<<5) 342 | #define WND_STATE_REDRAW_TITLE (1<<6) 343 | 344 | /* Window styles */ 345 | #define WND_STYLE_2D (0<<0) 346 | #define WND_STYLE_3D (1<<0) 347 | #define WND_STYLE_HIDE_TITLE (0<<1) 348 | #define WND_STYLE_SHOW_TITLE (1<<1) 349 | 350 | /* -------------------------------------------------------------------------------- */ 351 | /* -- BUTTON OBJECT -- */ 352 | /* -------------------------------------------------------------------------------- */ 353 | /* Button structure */ 354 | typedef struct 355 | { 356 | UG_U8 state; 357 | UG_U8 style; 358 | UG_COLOR fc; 359 | UG_COLOR bc; 360 | UG_COLOR afc; 361 | UG_COLOR abc; 362 | const UG_FONT* font; 363 | UG_U8 align; 364 | UG_S8 h_space; 365 | UG_S8 v_space; 366 | char* str; 367 | }UG_BUTTON; 368 | 369 | /* Default button IDs */ 370 | #define BTN_ID_0 OBJ_ID_0 371 | #define BTN_ID_1 OBJ_ID_1 372 | #define BTN_ID_2 OBJ_ID_2 373 | #define BTN_ID_3 OBJ_ID_3 374 | #define BTN_ID_4 OBJ_ID_4 375 | #define BTN_ID_5 OBJ_ID_5 376 | #define BTN_ID_6 OBJ_ID_6 377 | #define BTN_ID_7 OBJ_ID_7 378 | #define BTN_ID_8 OBJ_ID_8 379 | #define BTN_ID_9 OBJ_ID_9 380 | #define BTN_ID_10 OBJ_ID_10 381 | #define BTN_ID_11 OBJ_ID_11 382 | #define BTN_ID_12 OBJ_ID_12 383 | #define BTN_ID_13 OBJ_ID_13 384 | #define BTN_ID_14 OBJ_ID_14 385 | #define BTN_ID_15 OBJ_ID_15 386 | #define BTN_ID_16 OBJ_ID_16 387 | #define BTN_ID_17 OBJ_ID_17 388 | #define BTN_ID_18 OBJ_ID_18 389 | #define BTN_ID_19 OBJ_ID_19 390 | 391 | /* Button states */ 392 | #define BTN_STATE_RELEASED (0<<0) 393 | #define BTN_STATE_PRESSED (1<<0) 394 | #define BTN_STATE_ALWAYS_REDRAW (1<<1) 395 | 396 | /* Button style */ 397 | #define BTN_STYLE_2D (0<<0) 398 | #define BTN_STYLE_3D (1<<0) 399 | #define BTN_STYLE_TOGGLE_COLORS (1<<1) 400 | #define BTN_STYLE_USE_ALTERNATE_COLORS (1<<2) 401 | #define BTN_STYLE_NO_BORDERS (1<<3) 402 | #define BTN_STYLE_NO_FILL (1<<4) 403 | 404 | /* Button events */ 405 | #define BTN_EVENT_CLICKED OBJ_EVENT_CLICKED 406 | 407 | /* -------------------------------------------------------------------------------- */ 408 | /* -- CHECKBOX OBJECT -- */ 409 | /* -------------------------------------------------------------------------------- */ 410 | /* Checkbox structure */ 411 | typedef struct 412 | { 413 | UG_U8 state; 414 | UG_U8 style; 415 | UG_COLOR fc; 416 | UG_COLOR bc; 417 | UG_COLOR afc; 418 | UG_COLOR abc; 419 | const UG_FONT* font; 420 | UG_U8 align; 421 | UG_S8 h_space; 422 | UG_S8 v_space; 423 | char* str; 424 | UG_U8 checked; 425 | }UG_CHECKBOX; 426 | 427 | /* Default checkbox IDs */ 428 | #define CHB_ID_0 OBJ_ID_0 429 | #define CHB_ID_1 OBJ_ID_1 430 | #define CHB_ID_2 OBJ_ID_2 431 | #define CHB_ID_3 OBJ_ID_3 432 | #define CHB_ID_4 OBJ_ID_4 433 | #define CHB_ID_5 OBJ_ID_5 434 | #define CHB_ID_6 OBJ_ID_6 435 | #define CHB_ID_7 OBJ_ID_7 436 | #define CHB_ID_8 OBJ_ID_8 437 | #define CHB_ID_9 OBJ_ID_9 438 | #define CHB_ID_10 OBJ_ID_10 439 | #define CHB_ID_11 OBJ_ID_11 440 | #define CHB_ID_12 OBJ_ID_12 441 | #define CHB_ID_13 OBJ_ID_13 442 | #define CHB_ID_14 OBJ_ID_14 443 | #define CHB_ID_15 OBJ_ID_15 444 | #define CHB_ID_16 OBJ_ID_16 445 | #define CHB_ID_17 OBJ_ID_17 446 | #define CHB_ID_18 OBJ_ID_18 447 | #define CHB_ID_19 OBJ_ID_19 448 | 449 | /* Checkbox states */ 450 | #define CHB_STATE_RELEASED (0<<0) 451 | #define CHB_STATE_PRESSED (1<<0) 452 | #define CHB_STATE_ALWAYS_REDRAW (1<<1) 453 | 454 | /* Checkbox style */ 455 | #define CHB_STYLE_2D (0<<0) 456 | #define CHB_STYLE_3D (1<<0) 457 | #define CHB_STYLE_TOGGLE_COLORS (1<<1) 458 | #define CHB_STYLE_USE_ALTERNATE_COLORS (1<<2) 459 | #define CHB_STYLE_NO_BORDERS (1<<3) 460 | #define CHB_STYLE_NO_FILL (1<<4) 461 | 462 | /* Checkbox events */ 463 | #define CHB_EVENT_CLICKED OBJ_EVENT_CLICKED 464 | 465 | 466 | /* -------------------------------------------------------------------------------- */ 467 | /* -- TEXTBOX OBJECT -- */ 468 | /* -------------------------------------------------------------------------------- */ 469 | /* Textbox structure */ 470 | typedef struct 471 | { 472 | char* str; 473 | const UG_FONT* font; 474 | UG_U8 style; 475 | UG_COLOR fc; 476 | UG_COLOR bc; 477 | UG_U8 align; 478 | UG_S8 h_space; 479 | UG_S8 v_space; 480 | } UG_TEXTBOX; 481 | 482 | /* Default textbox IDs */ 483 | #define TXB_ID_0 OBJ_ID_0 484 | #define TXB_ID_1 OBJ_ID_1 485 | #define TXB_ID_2 OBJ_ID_2 486 | #define TXB_ID_3 OBJ_ID_3 487 | #define TXB_ID_4 OBJ_ID_4 488 | #define TXB_ID_5 OBJ_ID_5 489 | #define TXB_ID_6 OBJ_ID_6 490 | #define TXB_ID_7 OBJ_ID_7 491 | #define TXB_ID_8 OBJ_ID_8 492 | #define TXB_ID_9 OBJ_ID_9 493 | #define TXB_ID_10 OBJ_ID_10 494 | #define TXB_ID_11 OBJ_ID_11 495 | #define TXB_ID_12 OBJ_ID_12 496 | #define TXB_ID_13 OBJ_ID_13 497 | #define TXB_ID_14 OBJ_ID_14 498 | #define TXB_ID_15 OBJ_ID_15 499 | #define TXB_ID_16 OBJ_ID_16 500 | #define TXB_ID_17 OBJ_ID_17 501 | #define TXB_ID_18 OBJ_ID_18 502 | #define TXB_ID_19 OBJ_ID_19 503 | 504 | /* -------------------------------------------------------------------------------- */ 505 | /* -- IMAGE OBJECT -- */ 506 | /* -------------------------------------------------------------------------------- */ 507 | /* Image structure */ 508 | typedef struct 509 | { 510 | void* img; 511 | UG_U8 type; 512 | } UG_IMAGE; 513 | 514 | /* Default image IDs */ 515 | #define IMG_ID_0 OBJ_ID_0 516 | #define IMG_ID_1 OBJ_ID_1 517 | #define IMG_ID_2 OBJ_ID_2 518 | #define IMG_ID_3 OBJ_ID_3 519 | #define IMG_ID_4 OBJ_ID_4 520 | #define IMG_ID_5 OBJ_ID_5 521 | #define IMG_ID_6 OBJ_ID_6 522 | #define IMG_ID_7 OBJ_ID_7 523 | #define IMG_ID_8 OBJ_ID_8 524 | #define IMG_ID_9 OBJ_ID_9 525 | #define IMG_ID_10 OBJ_ID_10 526 | #define IMG_ID_11 OBJ_ID_11 527 | #define IMG_ID_12 OBJ_ID_12 528 | #define IMG_ID_13 OBJ_ID_13 529 | #define IMG_ID_14 OBJ_ID_14 530 | #define IMG_ID_15 OBJ_ID_15 531 | #define IMG_ID_16 OBJ_ID_16 532 | #define IMG_ID_17 OBJ_ID_17 533 | #define IMG_ID_18 OBJ_ID_18 534 | #define IMG_ID_19 OBJ_ID_19 535 | 536 | /* Image types */ 537 | #define IMG_TYPE_BMP (1<<0) 538 | 539 | /* -------------------------------------------------------------------------------- */ 540 | /* -- µGUI DRIVER -- */ 541 | /* -------------------------------------------------------------------------------- */ 542 | typedef struct 543 | { 544 | void* driver; 545 | UG_U8 state; 546 | } UG_DRIVER; 547 | 548 | #define DRIVER_REGISTERED (1<<0) 549 | #define DRIVER_ENABLED (1<<1) 550 | 551 | /* Supported drivers */ 552 | #define NUMBER_OF_DRIVERS 3 553 | #define DRIVER_DRAW_LINE 0 554 | #define DRIVER_FILL_FRAME 1 555 | #define DRIVER_FILL_AREA 2 556 | 557 | /* -------------------------------------------------------------------------------- */ 558 | /* -- µGUI CORE STRUCTURE -- */ 559 | /* -------------------------------------------------------------------------------- */ 560 | typedef struct 561 | { 562 | void (*pset)(UG_S16,UG_S16,UG_COLOR); 563 | UG_S16 x_dim; 564 | UG_S16 y_dim; 565 | UG_TOUCH touch; 566 | UG_WINDOW* next_window; 567 | UG_WINDOW* active_window; 568 | UG_WINDOW* last_window; 569 | struct 570 | { 571 | UG_S16 x_pos; 572 | UG_S16 y_pos; 573 | UG_S16 x_start; 574 | UG_S16 y_start; 575 | UG_S16 x_end; 576 | UG_S16 y_end; 577 | UG_COLOR fore_color; 578 | UG_COLOR back_color; 579 | } console; 580 | UG_FONT font; 581 | UG_S8 char_h_space; 582 | UG_S8 char_v_space; 583 | UG_COLOR fore_color; 584 | UG_COLOR back_color; 585 | UG_COLOR desktop_color; 586 | UG_U8 state; 587 | UG_DRIVER driver[NUMBER_OF_DRIVERS]; 588 | } UG_GUI; 589 | 590 | #define UG_SATUS_WAIT_FOR_UPDATE (1<<0) 591 | 592 | /* -------------------------------------------------------------------------------- */ 593 | /* -- µGUI COLORS -- */ 594 | /* -- Source: http://www.rapidtables.com/web/color/RGB_Color.htm -- */ 595 | /* -------------------------------------------------------------------------------- */ 596 | #ifdef USE_COLOR_RGB565 597 | #define C_MAROON 0x8000 598 | #define C_DARK_RED 0x8800 599 | #define C_BROWN 0xA145 600 | #define C_FIREBRICK 0xB104 601 | #define C_CRIMSON 0xD8A7 602 | #define C_RED 0xF800 603 | #define C_TOMATO 0xFB09 604 | #define C_CORAL 0xFBEA 605 | #define C_INDIAN_RED 0xCAEB 606 | #define C_LIGHT_CORAL 0xEC10 607 | #define C_DARK_SALMON 0xE4AF 608 | #define C_SALMON 0xF40E 609 | #define C_LIGHT_SALMON 0xFD0F 610 | #define C_ORANGE_RED 0xFA20 611 | #define C_DARK_ORANGE 0xFC60 612 | #define C_ORANGE 0xFD20 613 | #define C_GOLD 0xFEA0 614 | #define C_DARK_GOLDEN_ROD 0xB421 615 | #define C_GOLDEN_ROD 0xDD24 616 | #define C_PALE_GOLDEN_ROD 0xEF35 617 | #define C_DARK_KHAKI 0xBDAD 618 | #define C_KHAKI 0xEF31 619 | #define C_OLIVE 0x8400 620 | #define C_YELLOW 0xFFE0 621 | #define C_YELLOW_GREEN 0x9E66 622 | #define C_DARK_OLIVE_GREEN 0x5346 623 | #define C_OLIVE_DRAB 0x6C64 624 | #define C_LAWN_GREEN 0x7FC0 625 | #define C_CHART_REUSE 0x7FE0 626 | #define C_GREEN_YELLOW 0xAFE6 627 | #define C_DARK_GREEN 0x0320 628 | #define C_GREEN 0x07E0 629 | #define C_FOREST_GREEN 0x2444 630 | #define C_LIME 0x07E0 631 | #define C_LIME_GREEN 0x3666 632 | #define C_LIGHT_GREEN 0x9772 633 | #define C_PALE_GREEN 0x97D2 634 | #define C_DARK_SEA_GREEN 0x8DD1 635 | #define C_MEDIUM_SPRING_GREEN 0x07D3 636 | #define C_SPRING_GREEN 0x07EF 637 | #define C_SEA_GREEN 0x344B 638 | #define C_MEDIUM_AQUA_MARINE 0x6675 639 | #define C_MEDIUM_SEA_GREEN 0x3D8E 640 | #define C_LIGHT_SEA_GREEN 0x2595 641 | #define C_DARK_SLATE_GRAY 0x328A 642 | #define C_TEAL 0x0410 643 | #define C_DARK_CYAN 0x0451 644 | #define C_AQUA 0x07FF 645 | #define C_CYAN 0x07FF 646 | #define C_LIGHT_CYAN 0xDFFF 647 | #define C_DARK_TURQUOISE 0x0679 648 | #define C_TURQUOISE 0x46F9 649 | #define C_MEDIUM_TURQUOISE 0x4E99 650 | #define C_PALE_TURQUOISE 0xAF7D 651 | #define C_AQUA_MARINE 0x7FFA 652 | #define C_POWDER_BLUE 0xAEFC 653 | #define C_CADET_BLUE 0x64F3 654 | #define C_STEEL_BLUE 0x4C16 655 | #define C_CORN_FLOWER_BLUE 0x64BD 656 | #define C_DEEP_SKY_BLUE 0x05FF 657 | #define C_DODGER_BLUE 0x249F 658 | #define C_LIGHT_BLUE 0xAEBC 659 | #define C_SKY_BLUE 0x867D 660 | #define C_LIGHT_SKY_BLUE 0x867E 661 | #define C_MIDNIGHT_BLUE 0x18CE 662 | #define C_NAVY 0x0010 663 | #define C_DARK_BLUE 0x0011 664 | #define C_MEDIUM_BLUE 0x0019 665 | #define C_BLUE 0x001F 666 | #define C_ROYAL_BLUE 0x435B 667 | #define C_BLUE_VIOLET 0x897B 668 | #define C_INDIGO 0x4810 669 | #define C_DARK_SLATE_BLUE 0x49F1 670 | #define C_SLATE_BLUE 0x6AD9 671 | #define C_MEDIUM_SLATE_BLUE 0x7B5D 672 | #define C_MEDIUM_PURPLE 0x939B 673 | #define C_DARK_MAGENTA 0x8811 674 | #define C_DARK_VIOLET 0x901A 675 | #define C_DARK_ORCHID 0x9999 676 | #define C_MEDIUM_ORCHID 0xBABA 677 | #define C_PURPLE 0x8010 678 | #define C_THISTLE 0xD5FA 679 | #define C_PLUM 0xDD1B 680 | #define C_VIOLET 0xEC1D 681 | #define C_MAGENTA 0xF81F 682 | #define C_ORCHID 0xDB9A 683 | #define C_MEDIUM_VIOLET_RED 0xC0B0 684 | #define C_PALE_VIOLET_RED 0xDB92 685 | #define C_DEEP_PINK 0xF8B2 686 | #define C_HOT_PINK 0xFB56 687 | #define C_LIGHT_PINK 0xFDB7 688 | #define C_PINK 0xFDF9 689 | #define C_ANTIQUE_WHITE 0xF75A 690 | #define C_BEIGE 0xF7BB 691 | #define C_BISQUE 0xFF18 692 | #define C_BLANCHED_ALMOND 0xFF59 693 | #define C_WHEAT 0xF6F6 694 | #define C_CORN_SILK 0xFFBB 695 | #define C_LEMON_CHIFFON 0xFFD9 696 | #define C_LIGHT_GOLDEN_ROD_YELLOW 0xF7DA 697 | #define C_LIGHT_YELLOW 0xFFFB 698 | #define C_SADDLE_BROWN 0x8A22 699 | #define C_SIENNA 0x9A85 700 | #define C_CHOCOLATE 0xD344 701 | #define C_PERU 0xCC28 702 | #define C_SANDY_BROWN 0xF52C 703 | #define C_BURLY_WOOD 0xDDB0 704 | #define C_TAN 0xD591 705 | #define C_ROSY_BROWN 0xBC71 706 | #define C_MOCCASIN 0xFF16 707 | #define C_NAVAJO_WHITE 0xFEF5 708 | #define C_PEACH_PUFF 0xFED6 709 | #define C_MISTY_ROSE 0xFF1B 710 | #define C_LAVENDER_BLUSH 0xFF7E 711 | #define C_LINEN 0xF77C 712 | #define C_OLD_LACE 0xFFBC 713 | #define C_PAPAYA_WHIP 0xFF7A 714 | #define C_SEA_SHELL 0xFFBD 715 | #define C_MINT_CREAM 0xF7FE 716 | #define C_SLATE_GRAY 0x7412 717 | #define C_LIGHT_SLATE_GRAY 0x7453 718 | #define C_LIGHT_STEEL_BLUE 0xAE1B 719 | #define C_LAVENDER 0xE73E 720 | #define C_FLORAL_WHITE 0xFFDD 721 | #define C_ALICE_BLUE 0xEFBF 722 | #define C_GHOST_WHITE 0xF7BF 723 | #define C_HONEYDEW 0xEFFD 724 | #define C_IVORY 0xFFFD 725 | #define C_AZURE 0xEFFF 726 | #define C_SNOW 0xFFDE 727 | #define C_BLACK 0x0000 728 | #define C_DIM_GRAY 0x6B4D 729 | #define C_GRAY 0x8410 730 | #define C_DARK_GRAY 0xAD55 731 | #define C_SILVER 0xBDF7 732 | #define C_LIGHT_GRAY 0xD69A 733 | #define C_GAINSBORO 0xDEDB 734 | #define C_WHITE_SMOKE 0xF7BE 735 | #define C_WHITE 0xFFFF 736 | #endif 737 | 738 | #ifdef USE_COLOR_RGB888 739 | #define C_MAROON 0x800000 740 | #define C_DARK_RED 0x8B0000 741 | #define C_BROWN 0xA52A2A 742 | #define C_FIREBRICK 0xB22222 743 | #define C_CRIMSON 0xDC143C 744 | #define C_RED 0xFF0000 745 | #define C_TOMATO 0xFF6347 746 | #define C_CORAL 0xFF7F50 747 | #define C_INDIAN_RED 0xCD5C5C 748 | #define C_LIGHT_CORAL 0xF08080 749 | #define C_DARK_SALMON 0xE9967A 750 | #define C_SALMON 0xFA8072 751 | #define C_LIGHT_SALMON 0xFFA07A 752 | #define C_ORANGE_RED 0xFF4500 753 | #define C_DARK_ORANGE 0xFF8C00 754 | #define C_ORANGE 0xFFA500 755 | #define C_GOLD 0xFFD700 756 | #define C_DARK_GOLDEN_ROD 0xB8860B 757 | #define C_GOLDEN_ROD 0xDAA520 758 | #define C_PALE_GOLDEN_ROD 0xEEE8AA 759 | #define C_DARK_KHAKI 0xBDB76B 760 | #define C_KHAKI 0xF0E68C 761 | #define C_OLIVE 0x808000 762 | #define C_YELLOW 0xFFFF00 763 | #define C_YELLOW_GREEN 0x9ACD32 764 | #define C_DARK_OLIVE_GREEN 0x556B2F 765 | #define C_OLIVE_DRAB 0x6B8E23 766 | #define C_LAWN_GREEN 0x7CFC00 767 | #define C_CHART_REUSE 0x7FFF00 768 | #define C_GREEN_YELLOW 0xADFF2F 769 | #define C_DARK_GREEN 0x006400 770 | #define C_GREEN 0x00FF00 771 | #define C_FOREST_GREEN 0x228B22 772 | #define C_LIME 0x00FF00 773 | #define C_LIME_GREEN 0x32CD32 774 | #define C_LIGHT_GREEN 0x90EE90 775 | #define C_PALE_GREEN 0x98FB98 776 | #define C_DARK_SEA_GREEN 0x8FBC8F 777 | #define C_MEDIUM_SPRING_GREEN 0x00FA9A 778 | #define C_SPRING_GREEN 0x00FF7F 779 | #define C_SEA_GREEN 0x2E8B57 780 | #define C_MEDIUM_AQUA_MARINE 0x66CDAA 781 | #define C_MEDIUM_SEA_GREEN 0x3CB371 782 | #define C_LIGHT_SEA_GREEN 0x20B2AA 783 | #define C_DARK_SLATE_GRAY 0x2F4F4F 784 | #define C_TEAL 0x008080 785 | #define C_DARK_CYAN 0x008B8B 786 | #define C_AQUA 0x00FFFF 787 | #define C_CYAN 0x00FFFF 788 | #define C_LIGHT_CYAN 0xE0FFFF 789 | #define C_DARK_TURQUOISE 0x00CED1 790 | #define C_TURQUOISE 0x40E0D0 791 | #define C_MEDIUM_TURQUOISE 0x48D1CC 792 | #define C_PALE_TURQUOISE 0xAFEEEE 793 | #define C_AQUA_MARINE 0x7FFFD4 794 | #define C_POWDER_BLUE 0xB0E0E6 795 | #define C_CADET_BLUE 0x5F9EA0 796 | #define C_STEEL_BLUE 0x4682B4 797 | #define C_CORN_FLOWER_BLUE 0x6495ED 798 | #define C_DEEP_SKY_BLUE 0x00BFFF 799 | #define C_DODGER_BLUE 0x1E90FF 800 | #define C_LIGHT_BLUE 0xADD8E6 801 | #define C_SKY_BLUE 0x87CEEB 802 | #define C_LIGHT_SKY_BLUE 0x87CEFA 803 | #define C_MIDNIGHT_BLUE 0x191970 804 | #define C_NAVY 0x000080 805 | #define C_DARK_BLUE 0x00008B 806 | #define C_MEDIUM_BLUE 0x0000CD 807 | #define C_BLUE 0x0000FF 808 | #define C_ROYAL_BLUE 0x4169E1 809 | #define C_BLUE_VIOLET 0x8A2BE2 810 | #define C_INDIGO 0x4B0082 811 | #define C_DARK_SLATE_BLUE 0x483D8B 812 | #define C_SLATE_BLUE 0x6A5ACD 813 | #define C_MEDIUM_SLATE_BLUE 0x7B68EE 814 | #define C_MEDIUM_PURPLE 0x9370DB 815 | #define C_DARK_MAGENTA 0x8B008B 816 | #define C_DARK_VIOLET 0x9400D3 817 | #define C_DARK_ORCHID 0x9932CC 818 | #define C_MEDIUM_ORCHID 0xBA55D3 819 | #define C_PURPLE 0x800080 820 | #define C_THISTLE 0xD8BFD8 821 | #define C_PLUM 0xDDA0DD 822 | #define C_VIOLET 0xEE82EE 823 | #define C_MAGENTA 0xFF00FF 824 | #define C_ORCHID 0xDA70D6 825 | #define C_MEDIUM_VIOLET_RED 0xC71585 826 | #define C_PALE_VIOLET_RED 0xDB7093 827 | #define C_DEEP_PINK 0xFF1493 828 | #define C_HOT_PINK 0xFF69B4 829 | #define C_LIGHT_PINK 0xFFB6C1 830 | #define C_PINK 0xFFC0CB 831 | #define C_ANTIQUE_WHITE 0xFAEBD7 832 | #define C_BEIGE 0xF5F5DC 833 | #define C_BISQUE 0xFFE4C4 834 | #define C_BLANCHED_ALMOND 0xFFEBCD 835 | #define C_WHEAT 0xF5DEB3 836 | #define C_CORN_SILK 0xFFF8DC 837 | #define C_LEMON_CHIFFON 0xFFFACD 838 | #define C_LIGHT_GOLDEN_ROD_YELLOW 0xFAFAD2 839 | #define C_LIGHT_YELLOW 0xFFFFE0 840 | #define C_SADDLE_BROWN 0x8B4513 841 | #define C_SIENNA 0xA0522D 842 | #define C_CHOCOLATE 0xD2691E 843 | #define C_PERU 0xCD853F 844 | #define C_SANDY_BROWN 0xF4A460 845 | #define C_BURLY_WOOD 0xDEB887 846 | #define C_TAN 0xD2B48C 847 | #define C_ROSY_BROWN 0xBC8F8F 848 | #define C_MOCCASIN 0xFFE4B5 849 | #define C_NAVAJO_WHITE 0xFFDEAD 850 | #define C_PEACH_PUFF 0xFFDAB9 851 | #define C_MISTY_ROSE 0xFFE4E1 852 | #define C_LAVENDER_BLUSH 0xFFF0F5 853 | #define C_LINEN 0xFAF0E6 854 | #define C_OLD_LACE 0xFDF5E6 855 | #define C_PAPAYA_WHIP 0xFFEFD5 856 | #define C_SEA_SHELL 0xFFF5EE 857 | #define C_MINT_CREAM 0xF5FFFA 858 | #define C_SLATE_GRAY 0x708090 859 | #define C_LIGHT_SLATE_GRAY 0x778899 860 | #define C_LIGHT_STEEL_BLUE 0xB0C4DE 861 | #define C_LAVENDER 0xE6E6FA 862 | #define C_FLORAL_WHITE 0xFFFAF0 863 | #define C_ALICE_BLUE 0xF0F8FF 864 | #define C_GHOST_WHITE 0xF8F8FF 865 | #define C_HONEYDEW 0xF0FFF0 866 | #define C_IVORY 0xFFFFF0 867 | #define C_AZURE 0xF0FFFF 868 | #define C_SNOW 0xFFFAFA 869 | #define C_BLACK 0x000000 870 | #define C_DIM_GRAY 0x696969 871 | #define C_GRAY 0x808080 872 | #define C_DARK_GRAY 0xA9A9A9 873 | #define C_SILVER 0xC0C0C0 874 | #define C_LIGHT_GRAY 0xD3D3D3 875 | #define C_GAINSBORO 0xDCDCDC 876 | #define C_WHITE_SMOKE 0xF5F5F5 877 | #define C_WHITE 0xFFFFFF 878 | #endif 879 | 880 | /* -------------------------------------------------------------------------------- */ 881 | /* -- PROTOTYPES -- */ 882 | /* -------------------------------------------------------------------------------- */ 883 | /* Classic functions */ 884 | UG_S16 UG_Init( UG_GUI* g, void (*p)(UG_S16,UG_S16,UG_COLOR), UG_S16 x, UG_S16 y ); 885 | UG_S16 UG_SelectGUI( UG_GUI* g ); 886 | void UG_FontSelect( const UG_FONT* font ); 887 | void UG_FillScreen( UG_COLOR c ); 888 | void UG_FillFrame( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c ); 889 | void UG_FillRoundFrame( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_S16 r, UG_COLOR c ); 890 | void UG_DrawMesh( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c ); 891 | void UG_DrawFrame( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c ); 892 | void UG_DrawRoundFrame( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_S16 r, UG_COLOR c ); 893 | void UG_DrawPixel( UG_S16 x0, UG_S16 y0, UG_COLOR c ); 894 | void UG_DrawCircle( UG_S16 x0, UG_S16 y0, UG_S16 r, UG_COLOR c ); 895 | void UG_FillCircle( UG_S16 x0, UG_S16 y0, UG_S16 r, UG_COLOR c ); 896 | void UG_DrawArc( UG_S16 x0, UG_S16 y0, UG_S16 r, UG_U8 s, UG_COLOR c ); 897 | void UG_DrawLine( UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, UG_COLOR c ); 898 | void UG_PutString( UG_S16 x, UG_S16 y, char* str ); 899 | void UG_PutChar( char chr, UG_S16 x, UG_S16 y, UG_COLOR fc, UG_COLOR bc ); 900 | void UG_ConsolePutString( char* str ); 901 | void UG_ConsoleSetArea( UG_S16 xs, UG_S16 ys, UG_S16 xe, UG_S16 ye ); 902 | void UG_ConsoleSetForecolor( UG_COLOR c ); 903 | void UG_ConsoleSetBackcolor( UG_COLOR c ); 904 | void UG_SetForecolor( UG_COLOR c ); 905 | void UG_SetBackcolor( UG_COLOR c ); 906 | UG_S16 UG_GetXDim( void ); 907 | UG_S16 UG_GetYDim( void ); 908 | void UG_FontSetHSpace( UG_U16 s ); 909 | void UG_FontSetVSpace( UG_U16 s ); 910 | 911 | /* Miscellaneous functions */ 912 | void UG_WaitForUpdate( void ); 913 | void UG_Update( void ); 914 | void UG_DrawBMP( UG_S16 xp, UG_S16 yp, UG_BMP* bmp ); 915 | void UG_TouchUpdate( UG_S16 xp, UG_S16 yp, UG_U8 state ); 916 | 917 | /* Driver functions */ 918 | void UG_DriverRegister( UG_U8 type, void* driver ); 919 | void UG_DriverEnable( UG_U8 type ); 920 | void UG_DriverDisable( UG_U8 type ); 921 | 922 | /* Window functions */ 923 | UG_RESULT UG_WindowCreate( UG_WINDOW* wnd, UG_OBJECT* objlst, UG_U8 objcnt, void (*cb)( UG_MESSAGE* ) ); 924 | UG_RESULT UG_WindowDelete( UG_WINDOW* wnd ); 925 | UG_RESULT UG_WindowShow( UG_WINDOW* wnd ); 926 | UG_RESULT UG_WindowHide( UG_WINDOW* wnd ); 927 | UG_RESULT UG_WindowResize( UG_WINDOW* wnd, UG_S16 xs, UG_S16 ys, UG_S16 xe, UG_S16 ye ); 928 | UG_RESULT UG_WindowAlert( UG_WINDOW* wnd ); 929 | UG_RESULT UG_WindowSetForeColor( UG_WINDOW* wnd, UG_COLOR fc ); 930 | UG_RESULT UG_WindowSetBackColor( UG_WINDOW* wnd, UG_COLOR bc ); 931 | UG_RESULT UG_WindowSetTitleTextColor( UG_WINDOW* wnd, UG_COLOR c ); 932 | UG_RESULT UG_WindowSetTitleColor( UG_WINDOW* wnd, UG_COLOR c ); 933 | UG_RESULT UG_WindowSetTitleInactiveTextColor( UG_WINDOW* wnd, UG_COLOR c ); 934 | UG_RESULT UG_WindowSetTitleInactiveColor( UG_WINDOW* wnd, UG_COLOR c ); 935 | UG_RESULT UG_WindowSetTitleText( UG_WINDOW* wnd, char* str ); 936 | UG_RESULT UG_WindowSetTitleTextFont( UG_WINDOW* wnd, const UG_FONT* font ); 937 | UG_RESULT UG_WindowSetTitleTextHSpace( UG_WINDOW* wnd, UG_S8 hs ); 938 | UG_RESULT UG_WindowSetTitleTextVSpace( UG_WINDOW* wnd, UG_S8 vs ); 939 | UG_RESULT UG_WindowSetTitleTextAlignment( UG_WINDOW* wnd, UG_U8 align ); 940 | UG_RESULT UG_WindowSetTitleHeight( UG_WINDOW* wnd, UG_U8 height ); 941 | UG_RESULT UG_WindowSetXStart( UG_WINDOW* wnd, UG_S16 xs ); 942 | UG_RESULT UG_WindowSetYStart( UG_WINDOW* wnd, UG_S16 ys ); 943 | UG_RESULT UG_WindowSetXEnd( UG_WINDOW* wnd, UG_S16 xe ); 944 | UG_RESULT UG_WindowSetYEnd( UG_WINDOW* wnd, UG_S16 ye ); 945 | UG_RESULT UG_WindowSetStyle( UG_WINDOW* wnd, UG_U8 style ); 946 | UG_COLOR UG_WindowGetForeColor( UG_WINDOW* wnd ); 947 | UG_COLOR UG_WindowGetBackColor( UG_WINDOW* wnd ); 948 | UG_COLOR UG_WindowGetTitleTextColor( UG_WINDOW* wnd ); 949 | UG_COLOR UG_WindowGetTitleColor( UG_WINDOW* wnd ); 950 | UG_COLOR UG_WindowGetTitleInactiveTextColor( UG_WINDOW* wnd ); 951 | UG_COLOR UG_WindowGetTitleInactiveColor( UG_WINDOW* wnd ); 952 | char* UG_WindowGetTitleText( UG_WINDOW* wnd ); 953 | UG_FONT* UG_WindowGetTitleTextFont( UG_WINDOW* wnd ); 954 | UG_S8 UG_WindowGetTitleTextHSpace( UG_WINDOW* wnd ); 955 | UG_S8 UG_WindowGetTitleTextVSpace( UG_WINDOW* wnd ); 956 | UG_U8 UG_WindowGetTitleTextAlignment( UG_WINDOW* wnd ); 957 | UG_U8 UG_WindowGetTitleHeight( UG_WINDOW* wnd ); 958 | UG_S16 UG_WindowGetXStart( UG_WINDOW* wnd ); 959 | UG_S16 UG_WindowGetYStart( UG_WINDOW* wnd ); 960 | UG_S16 UG_WindowGetXEnd( UG_WINDOW* wnd ); 961 | UG_S16 UG_WindowGetYEnd( UG_WINDOW* wnd ); 962 | UG_U8 UG_WindowGetStyle( UG_WINDOW* wnd ); 963 | UG_RESULT UG_WindowGetArea( UG_WINDOW* wnd, UG_AREA* a ); 964 | UG_S16 UG_WindowGetInnerWidth( UG_WINDOW* wnd ); 965 | UG_S16 UG_WindowGetOuterWidth( UG_WINDOW* wnd ); 966 | UG_S16 UG_WindowGetInnerHeight( UG_WINDOW* wnd ); 967 | UG_S16 UG_WindowGetOuterHeight( UG_WINDOW* wnd ); 968 | 969 | /* Button functions */ 970 | UG_RESULT UG_ButtonCreate( UG_WINDOW* wnd, UG_BUTTON* btn, UG_U8 id, UG_S16 xs, UG_S16 ys, UG_S16 xe, UG_S16 ye ); 971 | UG_RESULT UG_ButtonDelete( UG_WINDOW* wnd, UG_U8 id ); 972 | UG_RESULT UG_ButtonShow( UG_WINDOW* wnd, UG_U8 id ); 973 | UG_RESULT UG_ButtonHide( UG_WINDOW* wnd, UG_U8 id ); 974 | UG_RESULT UG_ButtonSetForeColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR fc ); 975 | UG_RESULT UG_ButtonSetBackColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR bc ); 976 | UG_RESULT UG_ButtonSetAlternateForeColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR afc ); 977 | UG_RESULT UG_ButtonSetAlternateBackColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR abc ); 978 | UG_RESULT UG_ButtonSetText( UG_WINDOW* wnd, UG_U8 id, char* str ); 979 | UG_RESULT UG_ButtonSetFont( UG_WINDOW* wnd, UG_U8 id, const UG_FONT* font ); 980 | UG_RESULT UG_ButtonSetStyle( UG_WINDOW* wnd, UG_U8 id, UG_U8 style ); 981 | UG_RESULT UG_ButtonSetHSpace( UG_WINDOW* wnd, UG_U8 id, UG_S8 hs ); 982 | UG_RESULT UG_ButtonSetVSpace( UG_WINDOW* wnd, UG_U8 id, UG_S8 vs ); 983 | UG_RESULT UG_ButtonSetAlignment( UG_WINDOW* wnd, UG_U8 id, UG_U8 align ); 984 | UG_COLOR UG_ButtonGetForeColor( UG_WINDOW* wnd, UG_U8 id ); 985 | UG_COLOR UG_ButtonGetBackColor( UG_WINDOW* wnd, UG_U8 id ); 986 | UG_COLOR UG_ButtonGetAlternateForeColor( UG_WINDOW* wnd, UG_U8 id ); 987 | UG_COLOR UG_ButtonGetAlternateBackColor( UG_WINDOW* wnd, UG_U8 id ); 988 | char* UG_ButtonGetText( UG_WINDOW* wnd, UG_U8 id ); 989 | UG_FONT* UG_ButtonGetFont( UG_WINDOW* wnd, UG_U8 id ); 990 | UG_U8 UG_ButtonGetStyle( UG_WINDOW* wnd, UG_U8 id ); 991 | UG_S8 UG_ButtonGetHSpace( UG_WINDOW* wnd, UG_U8 id ); 992 | UG_S8 UG_ButtonGetVSpace( UG_WINDOW* wnd, UG_U8 id ); 993 | UG_U8 UG_ButtonGetAlignment( UG_WINDOW* wnd, UG_U8 id ); 994 | 995 | /* Checkbox functions */ 996 | UG_RESULT UG_CheckboxCreate( UG_WINDOW* wnd, UG_CHECKBOX* btn, UG_U8 id, UG_S16 xs, UG_S16 ys, UG_S16 xe, UG_S16 ye ); 997 | UG_RESULT UG_CheckboxDelete( UG_WINDOW* wnd, UG_U8 id ); 998 | UG_RESULT UG_CheckboxShow( UG_WINDOW* wnd, UG_U8 id ); 999 | UG_RESULT UG_CheckboxHide( UG_WINDOW* wnd, UG_U8 id ); 1000 | UG_RESULT UG_CheckboxSetCheched( UG_WINDOW* wnd, UG_U8 id, UG_U8 ch ); 1001 | UG_RESULT UG_CheckboxSetForeColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR fc ); 1002 | UG_RESULT UG_CheckboxSetBackColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR bc ); 1003 | UG_RESULT UG_CheckboxSetAlternateForeColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR afc ); 1004 | UG_RESULT UG_CheckboxSetAlternateBackColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR abc ); 1005 | UG_RESULT UG_CheckboxSetText( UG_WINDOW* wnd, UG_U8 id, char* str ); 1006 | UG_RESULT UG_CheckboxSetFont( UG_WINDOW* wnd, UG_U8 id, const UG_FONT* font ); 1007 | UG_RESULT UG_CheckboxSetStyle( UG_WINDOW* wnd, UG_U8 id, UG_U8 style ); 1008 | UG_RESULT UG_CheckboxSetHSpace( UG_WINDOW* wnd, UG_U8 id, UG_S8 hs ); 1009 | UG_RESULT UG_CheckboxSetVSpace( UG_WINDOW* wnd, UG_U8 id, UG_S8 vs ); 1010 | UG_RESULT UG_CheckboxSetAlignment( UG_WINDOW* wnd, UG_U8 id, UG_U8 align ); 1011 | UG_U8 UG_CheckboxGetChecked( UG_WINDOW* wnd, UG_U8 id ); 1012 | UG_COLOR UG_CheckboxGetForeColor( UG_WINDOW* wnd, UG_U8 id ); 1013 | UG_COLOR UG_CheckboxGetBackColor( UG_WINDOW* wnd, UG_U8 id ); 1014 | UG_COLOR UG_CheckboxGetAlternateForeColor( UG_WINDOW* wnd, UG_U8 id ); 1015 | UG_COLOR UG_CheckboxGetAlternateBackColor( UG_WINDOW* wnd, UG_U8 id ); 1016 | char* UG_CheckboxGetText( UG_WINDOW* wnd, UG_U8 id ); 1017 | UG_FONT* UG_CheckboxGetFont( UG_WINDOW* wnd, UG_U8 id ); 1018 | UG_U8 UG_CheckboxGetStyle( UG_WINDOW* wnd, UG_U8 id ); 1019 | UG_S8 UG_CheckboxGetHSpace( UG_WINDOW* wnd, UG_U8 id ); 1020 | UG_S8 UG_CheckboxGetVSpace( UG_WINDOW* wnd, UG_U8 id ); 1021 | UG_U8 UG_CheckboxGetAlignment( UG_WINDOW* wnd, UG_U8 id ); 1022 | 1023 | /* Textbox functions */ 1024 | UG_RESULT UG_TextboxCreate( UG_WINDOW* wnd, UG_TEXTBOX* txb, UG_U8 id, UG_S16 xs, UG_S16 ys, UG_S16 xe, UG_S16 ye ); 1025 | UG_RESULT UG_TextboxDelete( UG_WINDOW* wnd, UG_U8 id ); 1026 | UG_RESULT UG_TextboxShow( UG_WINDOW* wnd, UG_U8 id ); 1027 | UG_RESULT UG_TextboxHide( UG_WINDOW* wnd, UG_U8 id ); 1028 | UG_RESULT UG_TextboxSetForeColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR fc ); 1029 | UG_RESULT UG_TextboxSetBackColor( UG_WINDOW* wnd, UG_U8 id, UG_COLOR bc ); 1030 | UG_RESULT UG_TextboxSetText( UG_WINDOW* wnd, UG_U8 id, char* str ); 1031 | UG_RESULT UG_TextboxSetFont( UG_WINDOW* wnd, UG_U8 id, const UG_FONT* font ); 1032 | UG_RESULT UG_TextboxSetHSpace( UG_WINDOW* wnd, UG_U8 id, UG_S8 hs ); 1033 | UG_RESULT UG_TextboxSetVSpace( UG_WINDOW* wnd, UG_U8 id, UG_S8 vs ); 1034 | UG_RESULT UG_TextboxSetAlignment( UG_WINDOW* wnd, UG_U8 id, UG_U8 align ); 1035 | UG_COLOR UG_TextboxGetForeColor( UG_WINDOW* wnd, UG_U8 id ); 1036 | UG_COLOR UG_TextboxGetBackColor( UG_WINDOW* wnd, UG_U8 id ); 1037 | char* UG_TextboxGetText( UG_WINDOW* wnd, UG_U8 id ); 1038 | UG_FONT* UG_TextboxGetFont( UG_WINDOW* wnd, UG_U8 id ); 1039 | UG_S8 UG_TextboxGetHSpace( UG_WINDOW* wnd, UG_U8 id ); 1040 | UG_S8 UG_TextboxGetVSpace( UG_WINDOW* wnd, UG_U8 id ); 1041 | UG_U8 UG_TextboxGetAlignment( UG_WINDOW* wnd, UG_U8 id ); 1042 | 1043 | /* Image functions */ 1044 | UG_RESULT UG_ImageCreate( UG_WINDOW* wnd, UG_IMAGE* img, UG_U8 id, UG_S16 xs, UG_S16 ys, UG_S16 xe, UG_S16 ye ); 1045 | UG_RESULT UG_ImageDelete( UG_WINDOW* wnd, UG_U8 id ); 1046 | UG_RESULT UG_ImageShow( UG_WINDOW* wnd, UG_U8 id ); 1047 | UG_RESULT UG_ImageHide( UG_WINDOW* wnd, UG_U8 id ); 1048 | UG_RESULT UG_ImageSetBMP( UG_WINDOW* wnd, UG_U8 id, const UG_BMP* bmp ); 1049 | 1050 | 1051 | 1052 | #endif 1053 | -------------------------------------------------------------------------------- /examples/lib/UGUI/ugui_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __UGUI_CONFIG_H 2 | #define __UGUI_CONFIG_H 3 | 4 | /* -------------------------------------------------------------------------------- */ 5 | /* -- CONFIG SECTION -- */ 6 | /* -------------------------------------------------------------------------------- */ 7 | 8 | //#define USE_MULTITASKING 9 | 10 | /* Enable color mode */ 11 | #define USE_COLOR_RGB888 // RGB = 0xFF,0xFF,0xFF 12 | //#define USE_COLOR_RGB565 // RGB = 0bRRRRRGGGGGGBBBBB 13 | 14 | /* Enable needed fonts here */ 15 | //#define USE_FONT_4X6 16 | //#define USE_FONT_5X8 17 | //#define USE_FONT_5X12 18 | //#define USE_FONT_6X8 19 | //#define USE_FONT_6X10 20 | //#define USE_FONT_7X12 21 | //#define USE_FONT_8X8 22 | //#define USE_FONT_8X12_CYRILLIC 23 | //#define USE_FONT_8X12 24 | //#define USE_FONT_8X12 25 | //#define USE_FONT_8X14 26 | //#define USE_FONT_10X16 27 | //#define USE_FONT_12X16 28 | //#define USE_FONT_12X20 29 | //#define USE_FONT_16X26 30 | //#define USE_FONT_22X36 31 | //#define USE_FONT_24X40 32 | //#define USE_FONT_32X53 33 | 34 | /* Specify platform-dependent integer types here */ 35 | 36 | #define __UG_FONT_DATA const 37 | typedef uint8_t UG_U8; 38 | typedef int8_t UG_S8; 39 | typedef uint16_t UG_U16; 40 | typedef int16_t UG_S16; 41 | typedef uint32_t UG_U32; 42 | typedef int32_t UG_S32; 43 | 44 | 45 | /* Example for dsPIC33 46 | typedef unsigned char UG_U8; 47 | typedef signed char UG_S8; 48 | typedef unsigned int UG_U16; 49 | typedef signed int UG_S16; 50 | typedef unsigned long int UG_U32; 51 | typedef signed long int UG_S32; 52 | */ 53 | 54 | /* -------------------------------------------------------------------------------- */ 55 | /* -------------------------------------------------------------------------------- */ 56 | 57 | 58 | /* Feature enablers */ 59 | #define USE_PRERENDER_EVENT 60 | #define USE_POSTRENDER_EVENT 61 | 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /examples/mcp9808_basic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(mcp9808_basic 2 | main.c 3 | ) 4 | 5 | target_link_libraries(mcp9808_basic 6 | FreeRTOS-Kernel 7 | FreeRTOS-Kernel-Heap1 8 | pico_stdlib 9 | i2c_dma 10 | common 11 | ) 12 | 13 | pico_enable_stdio_usb(mcp9808_basic 0) 14 | pico_enable_stdio_uart(mcp9808_basic 1) 15 | 16 | pico_add_extra_outputs(mcp9808_basic) 17 | 18 | -------------------------------------------------------------------------------- /examples/mcp9808_basic/README.md: -------------------------------------------------------------------------------- 1 | # mcp9808_basic 2 | 3 | This example demonstrates how read the ambient temperature from an MCP9808 4 | temperature sensor. 5 | 6 | The MCP9808 is assumed to be at address 0x18 on I2C0 (GP4 and GP5). 7 | 8 | -------------------------------------------------------------------------------- /examples/mcp9808_basic/main.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "task.h" 3 | #include "pico/stdlib.h" 4 | #include "i2c_dma.h" 5 | #include "mprintf.h" 6 | 7 | static const uint8_t MCP9808_ADDR = 0x18; 8 | static const uint8_t MCP9808_TEMP_REG = 0x05; 9 | 10 | // After power-up the MCP9808 typically requires 250 ms to perform the first 11 | // conversion at the power-up default resolution. See datasheet. 12 | static const int32_t MCP9808_POWER_UP_DELAY_MS = 300; 13 | 14 | static void blink_led_task(void *args) { 15 | (void) args; 16 | 17 | gpio_init(PICO_DEFAULT_LED_PIN); 18 | gpio_set_dir(PICO_DEFAULT_LED_PIN, 1); 19 | gpio_put(PICO_DEFAULT_LED_PIN, !PICO_DEFAULT_LED_PIN_INVERTED); 20 | 21 | while (true) { 22 | gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); 23 | vTaskDelay(pdMS_TO_TICKS(500)); 24 | } 25 | } 26 | 27 | static double mcp9808_raw_temp_to_celsius(uint16_t raw_temp) { 28 | return (raw_temp & 0x0fff) / 16.0 - (raw_temp & 0x1000 ? 256 : 0); 29 | } 30 | 31 | static void mcp9808_task(void *args) { 32 | i2c_dma_t *i2c_dma = (i2c_dma_t *) args; 33 | 34 | vTaskDelay(pdMS_TO_TICKS(MCP9808_POWER_UP_DELAY_MS)); 35 | 36 | for (int err_cnt = 0, i = 0; true; i += 1) { 37 | uint16_t raw_temp; 38 | const int rc = i2c_dma_read_word_swapped( 39 | i2c_dma, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp 40 | ); 41 | 42 | if (rc != PICO_OK) { 43 | err_cnt += 1; 44 | mprintf("error (i: %d, rc: %d, errors: %d)\n", i, rc, err_cnt); 45 | } else { 46 | const double celsius = mcp9808_raw_temp_to_celsius(raw_temp); 47 | mprintf("temp: %.4f (i: %d, errors: %d)\n", celsius, i, err_cnt); 48 | } 49 | 50 | vTaskDelay(pdMS_TO_TICKS(1000)); 51 | } 52 | } 53 | 54 | int main(void) { 55 | stdio_init_all(); 56 | 57 | static i2c_dma_t *i2c0_dma; 58 | const int rc = i2c_dma_init(&i2c0_dma, i2c0, (1000 * 1000), 4, 5); 59 | if (rc != PICO_OK) { 60 | mprintf("can't configure I2C0\n"); 61 | return rc; 62 | } 63 | 64 | xTaskCreate( 65 | blink_led_task, 66 | "blink-led-task", 67 | configMINIMAL_STACK_SIZE, 68 | NULL, 69 | configMAX_PRIORITIES - 2, 70 | NULL 71 | ); 72 | 73 | xTaskCreate( 74 | mcp9808_task, 75 | "mcp9808-task", 76 | configMINIMAL_STACK_SIZE, 77 | i2c0_dma, 78 | configMAX_PRIORITIES - 2, 79 | NULL 80 | ); 81 | 82 | vTaskStartScheduler(); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /examples/mcp9808_max_speed/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(mcp9808_max_speed 2 | main.c 3 | ) 4 | 5 | target_link_libraries(mcp9808_max_speed 6 | FreeRTOS-Kernel 7 | FreeRTOS-Kernel-Heap1 8 | pico_stdlib 9 | i2c_dma 10 | common 11 | ) 12 | 13 | pico_enable_stdio_usb(mcp9808_max_speed 0) 14 | pico_enable_stdio_uart(mcp9808_max_speed 1) 15 | 16 | pico_add_extra_outputs(mcp9808_max_speed) 17 | 18 | -------------------------------------------------------------------------------- /examples/mcp9808_max_speed/README.md: -------------------------------------------------------------------------------- 1 | # mcp9808_max_speed 2 | 3 | The goal of this example is to use DMA based I2C functions to continuously 4 | read the 16-bit ambient temperature register on an MCP9808 temperature sensor 5 | in order to determine how often the temperature register can be read per 6 | second. 7 | 8 | The MCP9808 is assumed to be at address 0x18 on I2C0 (GP4 and GP5). 9 | 10 | At a baud rate of 1,000,000 the temperature register can be read 1,000,000 11 | times in approximately 72 seconds or 13888 times per second. 12 | 13 | Because DMA based I2C functions are used, the program does not spend any of 14 | its time polling for the I2C operations to complete which allows other tasks 15 | to be performed at the same time. 16 | 17 | In this program two others tasks are performed at the same time. The first 18 | task, `blink_led_task`, blinks an LED at a frequency of 1Hz. The second task, 19 | `waste_time_task`, increments a counter in an endless loop. 20 | 21 | In the 72 seconds that are required to read the temperature register 1,000,000 22 | times, `waste_time_task` can increment it's counter 1,300,000,000 times. Each 23 | iteration of the endless loop incrementing the counter executes 4 instructions 24 | requiring 5 processor cycles: 25 | 26 | ``` 27 | 100002ee: 46c0 nop ; 1 cycle 28 | 100002f0: 3b01 subs r3, #1 ; 1 cycle 29 | 100002f2: 2b00 cmp r3, #0 ; 1 cycle 30 | 100002f4: d1fb bne.n 100002ee ; 2 cycles 31 | ``` 32 | 33 | This information can be used to calculate approximately how much processor 34 | time DMA based I2C requires. 35 | 36 | Processor cycles per second required by `waste_time_task` to increment its 37 | counter: 38 | 39 | ``` 40 | 1.3e9 * 5 / 72 = 90277777 41 | ``` 42 | 43 | If the processor is running at 125MHz and we assume that all remaining 44 | processor cycles are used for DMA based I2C, then the number of processor 45 | cycles per second required for DMA based I2C is: 46 | 47 | ``` 48 | 125000000 - 90277777 = 34722223 49 | ``` 50 | 51 | The program spends 72.22% of its time incrementing the counter and 27.78% of 52 | its time reading from the temperature sensor. 53 | 54 | This can be compared with example 55 | [mcp9808_max_speed_sdk_blocking](../mcp9808_max_speed_sdk_blocking) 56 | which performs 1,000,000 reads in 62 seconds but spends 100% of its time 57 | reading from the temperature sensor as it uses the Pico SDK blocking I2C 58 | functions. 59 | 60 | 61 | Typical program output: 62 | 63 | ``` 64 | temp: 26.5000 (i: 0, errors: 0) 65 | temp: 26.5625 (i: 10000, errors: 0) 66 | temp: 26.5000 (i: 20000, errors: 0) 67 | temp: 26.5000 (i: 30000, errors: 0) 68 | temp: 26.5000 (i: 40000, errors: 0) 69 | temp: 26.5000 (i: 50000, errors: 0) 70 | temp: 26.5000 (i: 60000, errors: 0) 71 | temp: 26.5000 (i: 70000, errors: 0) 72 | 0.1 billion iterations 73 | temp: 26.5000 (i: 80000, errors: 0) 74 | temp: 26.5000 (i: 90000, errors: 0) 75 | temp: 26.5000 (i: 100000, errors: 0) 76 | temp: 26.5000 (i: 110000, errors: 0) 77 | temp: 26.5000 (i: 120000, errors: 0) 78 | temp: 26.5000 (i: 130000, errors: 0) 79 | temp: 26.5000 (i: 140000, errors: 0) 80 | 0.2 billion iterations 81 | temp: 26.5000 (i: 150000, errors: 0) 82 | temp: 26.5000 (i: 160000, errors: 0) 83 | temp: 26.5625 (i: 170000, errors: 0) 84 | temp: 26.5000 (i: 180000, errors: 0) 85 | temp: 26.5000 (i: 190000, errors: 0) 86 | temp: 26.5000 (i: 200000, errors: 0) 87 | temp: 26.5000 (i: 210000, errors: 0) 88 | temp: 26.5000 (i: 220000, errors: 0) 89 | 0.3 billion iterations 90 | temp: 26.5000 (i: 230000, errors: 0) 91 | temp: 26.5000 (i: 240000, errors: 0) 92 | temp: 26.5000 (i: 250000, errors: 0) 93 | temp: 26.5000 (i: 260000, errors: 0) 94 | temp: 26.5000 (i: 270000, errors: 0) 95 | temp: 26.5000 (i: 280000, errors: 0) 96 | temp: 26.5625 (i: 290000, errors: 0) 97 | temp: 26.5000 (i: 300000, errors: 0) 98 | 0.4 billion iterations 99 | temp: 26.5625 (i: 310000, errors: 0) 100 | temp: 26.5000 (i: 320000, errors: 0) 101 | temp: 26.5000 (i: 330000, errors: 0) 102 | temp: 26.5625 (i: 340000, errors: 0) 103 | temp: 26.5000 (i: 350000, errors: 0) 104 | temp: 26.5625 (i: 360000, errors: 0) 105 | temp: 26.5000 (i: 370000, errors: 0) 106 | temp: 26.5000 (i: 380000, errors: 0) 107 | 0.5 billion iterations 108 | temp: 26.5000 (i: 390000, errors: 0) 109 | temp: 26.5000 (i: 400000, errors: 0) 110 | temp: 26.5000 (i: 410000, errors: 0) 111 | temp: 26.5000 (i: 420000, errors: 0) 112 | temp: 26.5000 (i: 430000, errors: 0) 113 | temp: 26.5625 (i: 440000, errors: 0) 114 | temp: 26.5000 (i: 450000, errors: 0) 115 | 0.6 billion iterations 116 | temp: 26.5000 (i: 460000, errors: 0) 117 | temp: 26.5000 (i: 470000, errors: 0) 118 | temp: 26.5625 (i: 480000, errors: 0) 119 | temp: 26.5000 (i: 490000, errors: 0) 120 | temp: 26.5000 (i: 500000, errors: 0) 121 | temp: 26.5000 (i: 510000, errors: 0) 122 | temp: 26.5000 (i: 520000, errors: 0) 123 | temp: 26.5000 (i: 530000, errors: 0) 124 | 0.7 billion iterations 125 | temp: 26.5625 (i: 540000, errors: 0) 126 | temp: 26.5000 (i: 550000, errors: 0) 127 | temp: 26.5000 (i: 560000, errors: 0) 128 | temp: 26.5000 (i: 570000, errors: 0) 129 | temp: 26.5000 (i: 580000, errors: 0) 130 | temp: 26.5000 (i: 590000, errors: 0) 131 | temp: 26.5000 (i: 600000, errors: 0) 132 | temp: 26.5000 (i: 610000, errors: 0) 133 | 0.8 billion iterations 134 | temp: 26.5625 (i: 620000, errors: 0) 135 | temp: 26.5000 (i: 630000, errors: 0) 136 | temp: 26.5000 (i: 640000, errors: 0) 137 | temp: 26.5000 (i: 650000, errors: 0) 138 | temp: 26.5000 (i: 660000, errors: 0) 139 | temp: 26.5000 (i: 670000, errors: 0) 140 | temp: 26.5000 (i: 680000, errors: 0) 141 | 0.9 billion iterations 142 | temp: 26.5000 (i: 690000, errors: 0) 143 | temp: 26.5000 (i: 700000, errors: 0) 144 | temp: 26.4375 (i: 710000, errors: 0) 145 | temp: 26.5000 (i: 720000, errors: 0) 146 | temp: 26.5000 (i: 730000, errors: 0) 147 | temp: 26.5000 (i: 740000, errors: 0) 148 | temp: 26.5000 (i: 750000, errors: 0) 149 | temp: 26.5000 (i: 760000, errors: 0) 150 | 1.0 billion iterations 151 | temp: 26.5000 (i: 770000, errors: 0) 152 | temp: 26.5000 (i: 780000, errors: 0) 153 | temp: 26.5000 (i: 790000, errors: 0) 154 | temp: 26.5000 (i: 800000, errors: 0) 155 | temp: 26.5000 (i: 810000, errors: 0) 156 | temp: 26.5625 (i: 820000, errors: 0) 157 | temp: 26.5000 (i: 830000, errors: 0) 158 | temp: 26.5000 (i: 840000, errors: 0) 159 | 1.1 billion iterations 160 | temp: 26.5000 (i: 850000, errors: 0) 161 | temp: 26.5000 (i: 860000, errors: 0) 162 | temp: 26.5000 (i: 870000, errors: 0) 163 | temp: 26.5000 (i: 880000, errors: 0) 164 | temp: 26.4375 (i: 890000, errors: 0) 165 | temp: 26.5000 (i: 900000, errors: 0) 166 | temp: 26.5000 (i: 910000, errors: 0) 167 | temp: 26.5000 (i: 920000, errors: 0) 168 | 1.2 billion iterations 169 | temp: 26.5625 (i: 930000, errors: 0) 170 | temp: 26.5000 (i: 940000, errors: 0) 171 | temp: 26.5000 (i: 950000, errors: 0) 172 | temp: 26.5000 (i: 960000, errors: 0) 173 | temp: 26.4375 (i: 970000, errors: 0) 174 | temp: 26.4375 (i: 980000, errors: 0) 175 | temp: 26.5000 (i: 990000, errors: 0) 176 | 1.3 billion iterations 177 | temp: 26.5000 (i: 1000000, errors: 0) 178 | temp: 26.5000 (i: 1010000, errors: 0) 179 | temp: 26.5000 (i: 1020000, errors: 0) 180 | temp: 26.5000 (i: 1030000, errors: 0) 181 | temp: 26.5000 (i: 1040000, errors: 0) 182 | temp: 26.5000 (i: 1050000, errors: 0) 183 | temp: 26.5000 (i: 1060000, errors: 0) 184 | temp: 26.5000 (i: 1070000, errors: 0) 185 | 1.4 billion iterations 186 | temp: 26.5000 (i: 1080000, errors: 0) 187 | temp: 26.5000 (i: 1090000, errors: 0) 188 | temp: 26.5000 (i: 1100000, errors: 0) 189 | ... 190 | ``` 191 | 192 | -------------------------------------------------------------------------------- /examples/mcp9808_max_speed/main.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "task.h" 3 | #include "pico/stdlib.h" 4 | #include "i2c_dma.h" 5 | #include "mprintf.h" 6 | 7 | static const uint8_t MCP9808_ADDR = 0x18; 8 | static const uint8_t MCP9808_TEMP_REG = 0x05; 9 | 10 | // After power-up the MCP9808 typically requires 250 ms to perform the first 11 | // conversion at the power-up default resolution. See datasheet. 12 | static const int32_t MCP9808_POWER_UP_DELAY_MS = 300; 13 | 14 | static void blink_led_task(void *args) { 15 | (void) args; 16 | 17 | gpio_init(PICO_DEFAULT_LED_PIN); 18 | gpio_set_dir(PICO_DEFAULT_LED_PIN, 1); 19 | gpio_put(PICO_DEFAULT_LED_PIN, !PICO_DEFAULT_LED_PIN_INVERTED); 20 | 21 | while (true) { 22 | gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); 23 | vTaskDelay(pdMS_TO_TICKS(500)); 24 | } 25 | } 26 | 27 | static double mcp9808_raw_temp_to_celsius(uint16_t raw_temp) { 28 | return (raw_temp & 0x0fff) / 16.0 - (raw_temp & 0x1000 ? 256 : 0); 29 | } 30 | 31 | static void mcp9808_task(void *args) { 32 | i2c_dma_t *i2c_dma = (i2c_dma_t *) args; 33 | 34 | vTaskDelay(pdMS_TO_TICKS(MCP9808_POWER_UP_DELAY_MS)); 35 | 36 | for (int err_cnt = 0, i = 0; true; i += 1) { 37 | uint16_t raw_temp; 38 | const int rc = i2c_dma_read_word_swapped( 39 | i2c_dma, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp 40 | ); 41 | 42 | if (rc != PICO_OK) { 43 | err_cnt += 1; 44 | mprintf("error (i: %d, rc: %d, errors: %d)\n", i, rc, err_cnt); 45 | } else if (i % 10000 == 0) { 46 | const double celsius = mcp9808_raw_temp_to_celsius(raw_temp); 47 | mprintf("temp: %.4f (i: %d, errors: %d)\n", celsius, i, err_cnt); 48 | } 49 | } 50 | } 51 | 52 | static void waste_time_task(void *args) { 53 | (void) args; 54 | 55 | double billion_iterations = 0; 56 | 57 | while (true) { 58 | for (int j = 0; j != 100 * 1000 * 1000; j += 1) { 59 | __asm__("nop"); 60 | } 61 | 62 | billion_iterations += 0.1; 63 | 64 | mprintf("%.1f billion iterations\n", billion_iterations); 65 | } 66 | } 67 | 68 | int main(void) { 69 | stdio_init_all(); 70 | 71 | static i2c_dma_t *i2c0_dma; 72 | const int rc = i2c_dma_init(&i2c0_dma, i2c0, (1000 * 1000), 4, 5); 73 | if (rc != PICO_OK) { 74 | mprintf("can't configure I2C0\n"); 75 | return rc; 76 | } 77 | 78 | xTaskCreate( 79 | blink_led_task, 80 | "blink-led-task", 81 | configMINIMAL_STACK_SIZE, 82 | NULL, 83 | configMAX_PRIORITIES - 2, 84 | NULL 85 | ); 86 | 87 | xTaskCreate( 88 | mcp9808_task, 89 | "mcp9808-task", 90 | configMINIMAL_STACK_SIZE, 91 | i2c0_dma, 92 | configMAX_PRIORITIES - 2, 93 | NULL 94 | ); 95 | 96 | xTaskCreate( 97 | waste_time_task, 98 | "waste-time-task", 99 | configMINIMAL_STACK_SIZE, 100 | NULL, 101 | configMAX_PRIORITIES - 4, 102 | NULL 103 | ); 104 | 105 | vTaskStartScheduler(); 106 | } 107 | 108 | -------------------------------------------------------------------------------- /examples/mcp9808_max_speed_sdk_blocking/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(mcp9808_max_speed_sdk_blocking 2 | main.c 3 | ) 4 | 5 | target_link_libraries(mcp9808_max_speed_sdk_blocking 6 | pico_stdlib 7 | hardware_i2c 8 | ) 9 | 10 | pico_enable_stdio_usb(mcp9808_max_speed_sdk_blocking 0) 11 | pico_enable_stdio_uart(mcp9808_max_speed_sdk_blocking 1) 12 | 13 | pico_add_extra_outputs(mcp9808_max_speed_sdk_blocking) 14 | 15 | -------------------------------------------------------------------------------- /examples/mcp9808_max_speed_sdk_blocking/README.md: -------------------------------------------------------------------------------- 1 | # mcp9808_max_speed_sdk_blocking 2 | 3 | The goal of this example is use the Pico SDK blocking I2C functions to 4 | continuously read the 16-bit ambient temperature register on an MCP9808 5 | temperature sensor in order to determine how often the temperature register can 6 | be read per second. This can then be compared with the number of reads per 7 | second possible with DMA based I2C to ensure that DMA based I2C performance is 8 | reasonable. 9 | 10 | The MCP9808 is assumed to be at address 0x18 on I2C0 (GP4 and GP5). 11 | 12 | At a baud rate of 1,000,000 the temperature register can be read 1,000,000 13 | times in approximately 62 seconds or 16129 times per second. 14 | 15 | Because the Pico SDK blocking I2C functions are used, the program spends most 16 | of its time polling and waiting for the I2C operations to complete which 17 | prevents other tasks from being performed at the same time. 18 | 19 | -------------------------------------------------------------------------------- /examples/mcp9808_max_speed_sdk_blocking/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pico/stdlib.h" 3 | #include "hardware/i2c.h" 4 | 5 | static const uint8_t MCP9808_ADDR = 0x18; 6 | static const uint8_t MCP9808_TEMP_REG = 0x05; 7 | 8 | // After power-up the MCP9808 typically requires 250 ms to perform the first 9 | // conversion at the power-up default resolution. See datasheet. 10 | static const int32_t MCP9808_POWER_UP_DELAY_MS = 300; 11 | 12 | static double mcp9808_raw_temp_to_celsius(uint16_t raw_temp) { 13 | return (raw_temp & 0x0fff) / 16.0 - (raw_temp & 0x1000 ? 256 : 0); 14 | } 15 | 16 | static int read_word_swapped(i2c_inst_t *i2c, int addr, uint8_t reg, int16_t *word) { 17 | int rc = i2c_write_blocking(i2c, addr, ®, 1, true); 18 | if (rc < 1) { 19 | return rc; 20 | } else if (rc != 1) { 21 | return PICO_ERROR_GENERIC; 22 | } 23 | 24 | rc = i2c_read_blocking(i2c, addr, (uint8_t *) word, 2, false); 25 | if (rc < 1) { 26 | return rc; 27 | } else if (rc != 2) { 28 | return PICO_ERROR_GENERIC; 29 | } 30 | 31 | *word = *word << 8 | ((*word >> 8) & 0xff); 32 | 33 | return PICO_OK; 34 | } 35 | 36 | int main(void) { 37 | stdio_init_all(); 38 | 39 | i2c_init(i2c0, 1000 * 1000); 40 | gpio_set_function(4, GPIO_FUNC_I2C); 41 | gpio_set_function(5, GPIO_FUNC_I2C); 42 | gpio_pull_up(4); 43 | gpio_pull_up(5); 44 | 45 | sleep_ms(MCP9808_POWER_UP_DELAY_MS); 46 | 47 | for (int err_cnt = 0, i = 0; true; i += 1) { 48 | uint16_t raw_temp; 49 | const int rc = read_word_swapped( 50 | i2c0, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp 51 | ); 52 | 53 | if (rc != PICO_OK) { 54 | err_cnt += 1; 55 | printf("error (i: %d, rc: %d, errors: %d)\n", i, rc, err_cnt); 56 | } else if (i % 10000 == 0) { 57 | const double celsius = mcp9808_raw_temp_to_celsius(raw_temp); 58 | printf("temp: %.4f (i: %d)\n", celsius, i); 59 | } 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /examples/mcp9808_minimalistic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(mcp9808_minimalistic 2 | main.c 3 | ) 4 | 5 | target_link_libraries(mcp9808_minimalistic 6 | FreeRTOS-Kernel 7 | FreeRTOS-Kernel-Heap1 8 | pico_stdlib 9 | i2c_dma 10 | common 11 | ) 12 | 13 | pico_enable_stdio_usb(mcp9808_minimalistic 0) 14 | pico_enable_stdio_uart(mcp9808_minimalistic 1) 15 | 16 | pico_add_extra_outputs(mcp9808_minimalistic) 17 | 18 | -------------------------------------------------------------------------------- /examples/mcp9808_minimalistic/README.md: -------------------------------------------------------------------------------- 1 | # mcp9808_minimalistic 2 | 3 | A minimalistic example that continuously reads the temperature from an MCP9808 4 | temperature sensor and prints the temperature. Unlike other examples, this 5 | example doesn't do any error checking to keep the code as short as possible. 6 | 7 | The MCP9808 is assumed to be at address 0x18 on I2C0 (GP4 and GP5). 8 | 9 | -------------------------------------------------------------------------------- /examples/mcp9808_minimalistic/main.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "task.h" 3 | #include "pico/stdlib.h" 4 | #include "i2c_dma.h" 5 | #include "mprintf.h" 6 | 7 | static const uint8_t MCP9808_ADDR = 0x18; 8 | static const uint8_t MCP9808_TEMP_REG = 0x05; 9 | static const int32_t MCP9808_POWER_UP_DELAY_MS = 300; 10 | 11 | static void mcp9808_task(void *args) { 12 | (void) args; 13 | 14 | i2c_dma_t *i2c_dma; 15 | i2c_dma_init(&i2c_dma, i2c0, (1000 * 1000), 4, 5); 16 | 17 | vTaskDelay(pdMS_TO_TICKS(MCP9808_POWER_UP_DELAY_MS)); 18 | 19 | while (true) { 20 | uint16_t raw_temp; 21 | i2c_dma_read_word_swapped( 22 | i2c_dma, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp 23 | ); 24 | 25 | double temp = (raw_temp & 0x0fff) / 16.0 - (raw_temp & 0x1000 ? 256 : 0); 26 | 27 | mprintf("temp: %.4f\n", temp); 28 | 29 | vTaskDelay(pdMS_TO_TICKS(1000)); 30 | } 31 | } 32 | 33 | int main(void) { 34 | stdio_init_all(); 35 | 36 | xTaskCreate( 37 | mcp9808_task, "mcp9808-task", configMINIMAL_STACK_SIZE, 38 | NULL, configMAX_PRIORITIES - 2, NULL 39 | ); 40 | 41 | vTaskStartScheduler(); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /examples/mcp9808_test_all_i2c_functions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(mcp9808_test_all_i2c_functions 2 | main.c 3 | ) 4 | 5 | target_link_libraries(mcp9808_test_all_i2c_functions 6 | FreeRTOS-Kernel 7 | FreeRTOS-Kernel-Heap1 8 | pico_stdlib 9 | i2c_dma 10 | common 11 | ) 12 | 13 | pico_enable_stdio_usb(mcp9808_test_all_i2c_functions 0) 14 | pico_enable_stdio_uart(mcp9808_test_all_i2c_functions 1) 15 | 16 | pico_add_extra_outputs(mcp9808_test_all_i2c_functions) 17 | 18 | -------------------------------------------------------------------------------- /examples/mcp9808_test_all_i2c_functions/README.md: -------------------------------------------------------------------------------- 1 | # mcp9808_test_all_i2c_functions 2 | 3 | This example can be regarded as a simple test that uses an MCP9808 to verify 4 | that all DMA I2C functions do what they are supposed to do. 5 | 6 | The MCP9808 is assumed to be at address 0x18 on I2C0 (GP4 and GP5). 7 | 8 | -------------------------------------------------------------------------------- /examples/mcp9808_test_all_i2c_functions/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "FreeRTOS.h" 3 | #include "task.h" 4 | #include "pico/stdlib.h" 5 | #include "i2c_dma.h" 6 | #include "mprintf.h" 7 | 8 | static const uint8_t MCP9808_ADDR = 0x18; 9 | static const uint8_t MCP9808_CRIT_TEMP_REG = 0x04; 10 | static const uint8_t MCP9808_TEMP_REG = 0x05; 11 | static const uint8_t MCP9808_RESOLUTION_REG = 0x08; 12 | 13 | // After power-up the MCP9808 typically requires 250 ms to perform the first 14 | // conversion at the power-up default resolution. See datasheet. 15 | static const int32_t MCP9808_POWER_UP_DELAY_MS = 300; 16 | 17 | static void blink_led_task(void *args) { 18 | (void) args; 19 | 20 | gpio_init(PICO_DEFAULT_LED_PIN); 21 | gpio_set_dir(PICO_DEFAULT_LED_PIN, 1); 22 | gpio_put(PICO_DEFAULT_LED_PIN, !PICO_DEFAULT_LED_PIN_INVERTED); 23 | 24 | while (true) { 25 | gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); 26 | vTaskDelay(pdMS_TO_TICKS(500)); 27 | } 28 | } 29 | 30 | static double mcp9808_raw_temp_to_celsius(uint16_t raw_temp) { 31 | return (raw_temp & 0x0fff) / 16.0 - (raw_temp & 0x1000 ? 256 : 0); 32 | } 33 | 34 | static void dma_write_followed_by_dma_read(i2c_dma_t *i2c_dma) { 35 | mprintf("dma_write_followed_by_dma_read\n"); 36 | 37 | for (uint8_t resolution = 0; resolution <= 3; resolution += 1) { 38 | const uint8_t wbuf_a[2] = {MCP9808_RESOLUTION_REG, resolution}; 39 | int rc = i2c_dma_write(i2c_dma, MCP9808_ADDR, wbuf_a, 2); 40 | if (rc != PICO_OK) { 41 | mprintf(" 1st i2c_dma_write failed, rc: %d\n", rc); 42 | } else { 43 | const uint8_t wbuf_b[1] = {MCP9808_RESOLUTION_REG}; 44 | rc = i2c_dma_write(i2c_dma, MCP9808_ADDR, wbuf_b, 1); 45 | if (rc != PICO_OK) { 46 | mprintf(" 2nd i2c_dma_write failed, rc: %d\n", rc); 47 | } else { 48 | uint8_t rbuf[1]; 49 | rc = i2c_dma_read(i2c_dma, MCP9808_ADDR, rbuf, 1); 50 | if (rc != PICO_OK) { 51 | mprintf(" i2c_dma_read failed, rc: %d\n", rc); 52 | } else if (resolution != rbuf[0]) { 53 | mprintf(" expected resolution %d, got %d\n", resolution, rbuf[0]); 54 | } else { 55 | mprintf(" ok, resolution set to %d\n", resolution); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | 62 | static void dma_write_byte_followed_by_dma_read_byte(i2c_dma_t *i2c_dma) { 63 | mprintf("dma_write_byte_followed_by_dma_read_byte\n"); 64 | 65 | for (uint8_t resolution = 0; resolution <= 3; resolution += 1) { 66 | int rc = i2c_dma_write_byte( 67 | i2c_dma, MCP9808_ADDR, MCP9808_RESOLUTION_REG, resolution 68 | ); 69 | if (rc != PICO_OK) { 70 | mprintf(" i2c_dma_write_byte failed, rc: %d\n", rc); 71 | } else { 72 | uint8_t byte; 73 | rc = i2c_dma_read_byte( 74 | i2c_dma, MCP9808_ADDR, MCP9808_RESOLUTION_REG, &byte 75 | ); 76 | if (rc != PICO_OK) { 77 | mprintf(" i2c_dma_read_byte failed, rc: %d\n", rc); 78 | } else if (resolution != byte) { 79 | mprintf(" expected resolution %d, got %d\n", resolution, byte); 80 | } else { 81 | mprintf(" ok, resolution set to %d\n", resolution); 82 | } 83 | } 84 | } 85 | } 86 | 87 | static void dma_write_word_followed_by_dma_read_word(i2c_dma_t *i2c_dma) { 88 | mprintf("dma_write_word_followed_by_dma_read_word\n"); 89 | 90 | for (int i = 4; i >= 0; i -= 1) { 91 | uint16_t crit_temp = i << 9; 92 | 93 | int rc = i2c_dma_write_word( 94 | i2c_dma, 95 | MCP9808_ADDR, 96 | MCP9808_CRIT_TEMP_REG, 97 | crit_temp << 8 | crit_temp >> 8 98 | ); 99 | if (rc != PICO_OK) { 100 | mprintf(" i2c_dma_write_word failed, rc: %d\n", rc); 101 | } else { 102 | uint16_t word; 103 | rc = i2c_dma_read_word( 104 | i2c_dma, MCP9808_ADDR, MCP9808_CRIT_TEMP_REG, &word 105 | ); 106 | word = word << 8 | word >> 8; 107 | if (rc != PICO_OK) { 108 | mprintf(" i2c_dma_read_word failed, rc: %d\n", rc); 109 | } else if (crit_temp != word) { 110 | mprintf( 111 | " expected critical temperature 0x%04x, got 0x%04x\n", 112 | crit_temp, word 113 | ); 114 | } else { 115 | mprintf( 116 | " ok, critical temperature set to 0x%04x (%.4f)\n", 117 | crit_temp, mcp9808_raw_temp_to_celsius(crit_temp) 118 | ); 119 | } 120 | } 121 | } 122 | } 123 | 124 | static void dma_write_word_swapped_followed_by_dma_read_word_swapped( 125 | i2c_dma_t *i2c_dma 126 | ) { 127 | mprintf("dma_write_word_swapped_followed_by_dma_read_word_swapped\n"); 128 | 129 | for (int i = 4; i >= 0; i -= 1) { 130 | uint16_t crit_temp = i << 9; 131 | 132 | int rc = i2c_dma_write_word_swapped( 133 | i2c_dma, MCP9808_ADDR, MCP9808_CRIT_TEMP_REG, crit_temp 134 | ); 135 | if (rc != PICO_OK) { 136 | mprintf(" i2c_dma_write_word_swapped failed, rc: %d\n", rc); 137 | } else { 138 | uint16_t word; 139 | rc = i2c_dma_read_word_swapped( 140 | i2c_dma, MCP9808_ADDR, MCP9808_CRIT_TEMP_REG, &word 141 | ); 142 | if (rc != PICO_OK) { 143 | mprintf(" i2c_dma_read_word_swapped failed, rc: %d\n", rc); 144 | } else if (crit_temp != word) { 145 | mprintf( 146 | " expected critical temperature 0x%04x, got 0x%04x\n", 147 | crit_temp, word 148 | ); 149 | } else { 150 | mprintf( 151 | " ok, critical temperature set to 0x%04x (%.4f)\n", 152 | crit_temp, mcp9808_raw_temp_to_celsius(crit_temp) 153 | ); 154 | } 155 | } 156 | } 157 | } 158 | 159 | static void mcp9808_task(void *args) { 160 | i2c_dma_t *i2c_dma = (i2c_dma_t *) args; 161 | 162 | vTaskDelay(pdMS_TO_TICKS(MCP9808_POWER_UP_DELAY_MS)); 163 | 164 | mprintf("----------------------------------------\n"); 165 | 166 | dma_write_followed_by_dma_read(i2c_dma); 167 | dma_write_byte_followed_by_dma_read_byte(i2c_dma); 168 | dma_write_word_followed_by_dma_read_word(i2c_dma); 169 | dma_write_word_swapped_followed_by_dma_read_word_swapped(i2c_dma); 170 | 171 | while (true) { 172 | vTaskDelay(pdMS_TO_TICKS(10000)); 173 | } 174 | } 175 | 176 | int main(void) { 177 | stdio_init_all(); 178 | 179 | static i2c_dma_t *i2c0_dma; 180 | const int rc = i2c_dma_init(&i2c0_dma, i2c0, (1000 * 1000), 4, 5); 181 | if (rc != PICO_OK) { 182 | mprintf("can't configure I2C0\n"); 183 | return rc; 184 | } 185 | 186 | xTaskCreate( 187 | blink_led_task, 188 | "blink-led-task", 189 | configMINIMAL_STACK_SIZE, 190 | NULL, 191 | configMAX_PRIORITIES - 2, 192 | NULL 193 | ); 194 | 195 | xTaskCreate( 196 | mcp9808_task, 197 | "mcp9808-task", 198 | configMINIMAL_STACK_SIZE, 199 | i2c0_dma, 200 | configMAX_PRIORITIES - 2, 201 | NULL 202 | ); 203 | 204 | vTaskStartScheduler(); 205 | } 206 | 207 | -------------------------------------------------------------------------------- /examples/mcp9808_x2_max_speed/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(mcp9808_x2_max_speed 2 | main.c 3 | ) 4 | 5 | target_link_libraries(mcp9808_x2_max_speed 6 | FreeRTOS-Kernel 7 | FreeRTOS-Kernel-Heap1 8 | pico_stdlib 9 | i2c_dma 10 | common 11 | ) 12 | 13 | pico_enable_stdio_usb(mcp9808_x2_max_speed 0) 14 | pico_enable_stdio_uart(mcp9808_x2_max_speed 1) 15 | 16 | pico_add_extra_outputs(mcp9808_x2_max_speed) 17 | 18 | -------------------------------------------------------------------------------- /examples/mcp9808_x2_max_speed/README.md: -------------------------------------------------------------------------------- 1 | # mcp9808_x2_max_speed 2 | 3 | The goal of this example is to use DMA based I2C functions to continuously 4 | read the 16-bit ambient temperature register on two MCP9808 temperature 5 | sensors concurrently in order to determine how often the temperature registers 6 | can be read per second. 7 | 8 | This example is similar to example `mcp9808_max_speed` but it reads the 9 | temperature from two MCP9808 temperature sensors concurrently rather than 10 | from just one sensor. 11 | 12 | The example assumes the following setup: 13 | 14 | - An MCP9808 temperature sensor at address 0x18 on I2C0 (GP4 and GP5) 15 | - An MCP9808 temperature sensor at address 0x18 on I2C1 (GP6 and GP7) 16 | 17 | At a baud rate of 1,000,000 the temperature register on each MCP9808 18 | temperature sensors can be read 1,000,000 times in approximately 74 seconds or 19 | 13513 times per second giving a total of 27026 reads per second. 20 | 21 | Because DMA based I2C functions are used, the program does not spend any of 22 | its time polling for the I2C operations to complete which allows other tasks 23 | to be performed at the same time. 24 | 25 | In this program two others tasks are performed at the same time. The first 26 | task, `blink_led_task`, blinks an LED at a frequency of 1Hz. The second task, 27 | `waste_time_task`, increments a counter in an endless loop. 28 | 29 | In the 74 seconds that are required to read the temperature register on each 30 | MCP9808 temperature sensor 1,000,000 times, `waste_time_task` can increment 31 | it's counter 800,000,000 times. Each iteration of the endless loop 32 | incrementing the counter executes 4 instructions requiring 5 processor cycles: 33 | 34 | ``` 35 | 100002ee: 46c0 nop ; 1 cycle 36 | 100002f0: 3b01 subs r3, #1 ; 1 cycle 37 | 100002f2: 2b00 cmp r3, #0 ; 1 cycle 38 | 100002f4: d1fb bne.n 100002ee ; 2 cycles 39 | ``` 40 | 41 | This information can be used to calculate approximately how much processor 42 | time DMA based I2C requires. 43 | 44 | Processor cycles per second required by `waste_time_task` to increment its 45 | counter: 46 | 47 | ``` 48 | 0.8e9 * 5 / 74 = 54054054 49 | ``` 50 | 51 | If the processor is running at 125MHz and we assume that all remaining 52 | processor cycles are used for DMA based I2C, then the number of processor 53 | cycles per second required for DMA based I2C is: 54 | 55 | ``` 56 | 125000000 - 54054054 = 70945946 57 | ``` 58 | 59 | The program spends 43.24% of its time incrementing the counter and 56.76% of 60 | its time reading from the two temperature sensors. 61 | 62 | This can be compared with example [mcp9808_max_speed](../mcp9808_max_speed) 63 | which performs 1,000,000 reads in 72 seconds and spends 72.22% of its time 64 | incrementing the counter and 27.78% of its time reading from a single 65 | temperature sensor. 66 | 67 | Typical program output: 68 | 69 | ``` 70 | bus 0, temp: 27.3750 (i: 0, errors: 0) 71 | bus 1, temp: 27.2500 (i: 0, errors: 0) 72 | bus 0, temp: 27.3750 (i: 10000, errors: 0) 73 | bus 1, temp: 27.3125 (i: 10000, errors: 0) 74 | bus 0, temp: 27.3750 (i: 20000, errors: 0) 75 | bus 1, temp: 27.2500 (i: 20000, errors: 0) 76 | bus 0, temp: 27.3750 (i: 30000, errors: 0) 77 | bus 1, temp: 27.2500 (i: 30000, errors: 0) 78 | bus 0, temp: 27.3750 (i: 40000, errors: 0) 79 | bus 1, temp: 27.2500 (i: 40000, errors: 0) 80 | bus 0, temp: 27.3750 (i: 50000, errors: 0) 81 | bus 1, temp: 27.2500 (i: 50000, errors: 0) 82 | bus 0, temp: 27.3750 (i: 60000, errors: 0) 83 | bus 1, temp: 27.3125 (i: 60000, errors: 0) 84 | bus 0, temp: 27.3750 (i: 70000, errors: 0) 85 | bus 1, temp: 27.2500 (i: 70000, errors: 0) 86 | bus 0, temp: 27.3750 (i: 80000, errors: 0) 87 | bus 1, temp: 27.3125 (i: 80000, errors: 0) 88 | bus 0, temp: 27.3750 (i: 90000, errors: 0) 89 | bus 1, temp: 27.2500 (i: 90000, errors: 0) 90 | bus 0, temp: 27.3750 (i: 100000, errors: 0) 91 | bus 1, temp: 27.3125 (i: 100000, errors: 0) 92 | bus 0, temp: 27.3750 (i: 110000, errors: 0) 93 | bus 1, temp: 27.2500 (i: 110000, errors: 0) 94 | 0.1 billion iterations 95 | bus 0, temp: 27.3750 (i: 120000, errors: 0) 96 | bus 1, temp: 27.3125 (i: 120000, errors: 0) 97 | bus 0, temp: 27.3750 (i: 130000, errors: 0) 98 | bus 1, temp: 27.3125 (i: 130000, errors: 0) 99 | bus 0, temp: 27.3750 (i: 140000, errors: 0) 100 | bus 1, temp: 27.3125 (i: 140000, errors: 0) 101 | bus 0, temp: 27.4375 (i: 150000, errors: 0) 102 | bus 1, temp: 27.3125 (i: 150000, errors: 0) 103 | bus 0, temp: 27.3750 (i: 160000, errors: 0) 104 | bus 1, temp: 27.2500 (i: 160000, errors: 0) 105 | bus 0, temp: 27.3750 (i: 170000, errors: 0) 106 | bus 1, temp: 27.3125 (i: 170000, errors: 0) 107 | bus 0, temp: 27.3750 (i: 180000, errors: 0) 108 | bus 1, temp: 27.3125 (i: 180000, errors: 0) 109 | bus 0, temp: 27.3750 (i: 190000, errors: 0) 110 | bus 1, temp: 27.3125 (i: 190000, errors: 0) 111 | bus 0, temp: 27.3750 (i: 200000, errors: 0) 112 | bus 1, temp: 27.2500 (i: 200000, errors: 0) 113 | bus 0, temp: 27.3750 (i: 210000, errors: 0) 114 | bus 1, temp: 27.3125 (i: 210000, errors: 0) 115 | bus 0, temp: 27.3750 (i: 220000, errors: 0) 116 | bus 1, temp: 27.3125 (i: 220000, errors: 0) 117 | bus 0, temp: 27.3750 (i: 230000, errors: 0) 118 | bus 1, temp: 27.3125 (i: 230000, errors: 0) 119 | bus 0, temp: 27.3750 (i: 240000, errors: 0) 120 | bus 1, temp: 27.3125 (i: 240000, errors: 0) 121 | 0.2 billion iterations 122 | bus 0, temp: 27.3750 (i: 250000, errors: 0) 123 | bus 1, temp: 27.3125 (i: 250000, errors: 0) 124 | bus 0, temp: 27.3750 (i: 260000, errors: 0) 125 | bus 1, temp: 27.2500 (i: 260000, errors: 0) 126 | bus 0, temp: 27.3750 (i: 270000, errors: 0) 127 | bus 1, temp: 27.2500 (i: 270000, errors: 0) 128 | bus 0, temp: 27.3750 (i: 280000, errors: 0) 129 | bus 1, temp: 27.3125 (i: 280000, errors: 0) 130 | bus 0, temp: 27.4375 (i: 290000, errors: 0) 131 | bus 1, temp: 27.3125 (i: 290000, errors: 0) 132 | bus 0, temp: 27.3750 (i: 300000, errors: 0) 133 | bus 1, temp: 27.3125 (i: 300000, errors: 0) 134 | bus 0, temp: 27.4375 (i: 310000, errors: 0) 135 | bus 1, temp: 27.3125 (i: 310000, errors: 0) 136 | bus 0, temp: 27.3750 (i: 320000, errors: 0) 137 | bus 1, temp: 27.3125 (i: 320000, errors: 0) 138 | bus 0, temp: 27.3750 (i: 330000, errors: 0) 139 | bus 1, temp: 27.2500 (i: 330000, errors: 0) 140 | bus 0, temp: 27.4375 (i: 340000, errors: 0) 141 | bus 1, temp: 27.3125 (i: 340000, errors: 0) 142 | bus 0, temp: 27.3750 (i: 350000, errors: 0) 143 | bus 1, temp: 27.2500 (i: 350000, errors: 0) 144 | bus 0, temp: 27.3750 (i: 360000, errors: 0) 145 | bus 1, temp: 27.3125 (i: 360000, errors: 0) 146 | 0.3 billion iterations 147 | bus 0, temp: 27.3750 (i: 370000, errors: 0) 148 | bus 1, temp: 27.3125 (i: 370000, errors: 0) 149 | bus 0, temp: 27.3750 (i: 380000, errors: 0) 150 | bus 1, temp: 27.2500 (i: 380000, errors: 0) 151 | bus 0, temp: 27.4375 (i: 390000, errors: 0) 152 | bus 1, temp: 27.3125 (i: 390000, errors: 0) 153 | bus 0, temp: 27.3750 (i: 400000, errors: 0) 154 | bus 1, temp: 27.3125 (i: 400000, errors: 0) 155 | bus 0, temp: 27.3750 (i: 410000, errors: 0) 156 | bus 1, temp: 27.3125 (i: 410000, errors: 0) 157 | bus 0, temp: 27.4375 (i: 420000, errors: 0) 158 | bus 1, temp: 27.3125 (i: 420000, errors: 0) 159 | bus 0, temp: 27.3750 (i: 430000, errors: 0) 160 | bus 1, temp: 27.3125 (i: 430000, errors: 0) 161 | bus 0, temp: 27.3750 (i: 440000, errors: 0) 162 | bus 1, temp: 27.2500 (i: 440000, errors: 0) 163 | bus 0, temp: 27.3750 (i: 450000, errors: 0) 164 | bus 1, temp: 27.3125 (i: 450000, errors: 0) 165 | bus 0, temp: 27.3750 (i: 460000, errors: 0) 166 | bus 1, temp: 27.2500 (i: 460000, errors: 0) 167 | bus 0, temp: 27.3750 (i: 470000, errors: 0) 168 | bus 1, temp: 27.3125 (i: 470000, errors: 0) 169 | bus 0, temp: 27.3750 (i: 480000, errors: 0) 170 | bus 1, temp: 27.3125 (i: 480000, errors: 0) 171 | bus 0, temp: 27.4375 (i: 490000, errors: 0) 172 | bus 1, temp: 27.3125 (i: 490000, errors: 0) 173 | 0.4 billion iterations 174 | bus 0, temp: 27.3750 (i: 500000, errors: 0) 175 | bus 1, temp: 27.3125 (i: 500000, errors: 0) 176 | bus 0, temp: 27.4375 (i: 510000, errors: 0) 177 | bus 1, temp: 27.3125 (i: 510000, errors: 0) 178 | bus 0, temp: 27.3750 (i: 520000, errors: 0) 179 | bus 1, temp: 27.2500 (i: 520000, errors: 0) 180 | bus 0, temp: 27.3750 (i: 530000, errors: 0) 181 | bus 1, temp: 27.3125 (i: 530000, errors: 0) 182 | bus 0, temp: 27.3750 (i: 540000, errors: 0) 183 | bus 1, temp: 27.3125 (i: 540000, errors: 0) 184 | bus 0, temp: 27.3750 (i: 550000, errors: 0) 185 | bus 1, temp: 27.3125 (i: 550000, errors: 0) 186 | bus 0, temp: 27.3750 (i: 560000, errors: 0) 187 | bus 1, temp: 27.2500 (i: 560000, errors: 0) 188 | bus 0, temp: 27.3750 (i: 570000, errors: 0) 189 | bus 1, temp: 27.3125 (i: 570000, errors: 0) 190 | bus 0, temp: 27.4375 (i: 580000, errors: 0) 191 | bus 1, temp: 27.3125 (i: 580000, errors: 0) 192 | bus 0, temp: 27.4375 (i: 590000, errors: 0) 193 | bus 1, temp: 27.3125 (i: 590000, errors: 0) 194 | bus 0, temp: 27.3750 (i: 600000, errors: 0) 195 | bus 1, temp: 27.3125 (i: 600000, errors: 0) 196 | bus 0, temp: 27.3750 (i: 610000, errors: 0) 197 | bus 1, temp: 27.3125 (i: 610000, errors: 0) 198 | bus 0, temp: 27.4375 (i: 620000, errors: 0) 199 | bus 1, temp: 27.3125 (i: 620000, errors: 0) 200 | 0.5 billion iterations 201 | bus 0, temp: 27.3750 (i: 630000, errors: 0) 202 | bus 1, temp: 27.3125 (i: 630000, errors: 0) 203 | bus 0, temp: 27.4375 (i: 640000, errors: 0) 204 | bus 1, temp: 27.3125 (i: 640000, errors: 0) 205 | bus 0, temp: 27.4375 (i: 650000, errors: 0) 206 | bus 1, temp: 27.3125 (i: 650000, errors: 0) 207 | bus 0, temp: 27.3750 (i: 660000, errors: 0) 208 | bus 1, temp: 27.3125 (i: 660000, errors: 0) 209 | bus 0, temp: 27.4375 (i: 670000, errors: 0) 210 | bus 1, temp: 27.3750 (i: 670000, errors: 0) 211 | bus 0, temp: 27.3750 (i: 680000, errors: 0) 212 | bus 1, temp: 27.3125 (i: 680000, errors: 0) 213 | bus 0, temp: 27.3750 (i: 690000, errors: 0) 214 | bus 1, temp: 27.2500 (i: 690000, errors: 0) 215 | bus 0, temp: 27.3750 (i: 700000, errors: 0) 216 | bus 1, temp: 27.3125 (i: 700000, errors: 0) 217 | bus 0, temp: 27.3750 (i: 710000, errors: 0) 218 | bus 1, temp: 27.3125 (i: 710000, errors: 0) 219 | bus 0, temp: 27.3750 (i: 720000, errors: 0) 220 | bus 1, temp: 27.3125 (i: 720000, errors: 0) 221 | bus 0, temp: 27.3750 (i: 730000, errors: 0) 222 | bus 1, temp: 27.3125 (i: 730000, errors: 0) 223 | bus 0, temp: 27.4375 (i: 740000, errors: 0) 224 | bus 1, temp: 27.3125 (i: 740000, errors: 0) 225 | 0.6 billion iterations 226 | bus 0, temp: 27.3750 (i: 750000, errors: 0) 227 | bus 1, temp: 27.3125 (i: 750000, errors: 0) 228 | bus 0, temp: 27.3750 (i: 760000, errors: 0) 229 | bus 1, temp: 27.3125 (i: 760000, errors: 0) 230 | bus 0, temp: 27.4375 (i: 770000, errors: 0) 231 | bus 1, temp: 27.3125 (i: 770000, errors: 0) 232 | bus 0, temp: 27.3750 (i: 780000, errors: 0) 233 | bus 1, temp: 27.3125 (i: 780000, errors: 0) 234 | bus 0, temp: 27.3750 (i: 790000, errors: 0) 235 | bus 1, temp: 27.3125 (i: 790000, errors: 0) 236 | bus 0, temp: 27.4375 (i: 800000, errors: 0) 237 | bus 1, temp: 27.3125 (i: 800000, errors: 0) 238 | bus 0, temp: 27.4375 (i: 810000, errors: 0) 239 | bus 1, temp: 27.3125 (i: 810000, errors: 0) 240 | bus 0, temp: 27.3750 (i: 820000, errors: 0) 241 | bus 1, temp: 27.3125 (i: 820000, errors: 0) 242 | bus 0, temp: 27.3750 (i: 830000, errors: 0) 243 | bus 1, temp: 27.3125 (i: 830000, errors: 0) 244 | bus 0, temp: 27.3750 (i: 840000, errors: 0) 245 | bus 1, temp: 27.3125 (i: 840000, errors: 0) 246 | bus 0, temp: 27.4375 (i: 850000, errors: 0) 247 | bus 1, temp: 27.3125 (i: 850000, errors: 0) 248 | bus 0, temp: 27.3750 (i: 860000, errors: 0) 249 | bus 1, temp: 27.3125 (i: 860000, errors: 0) 250 | bus 0, temp: 27.3750 (i: 870000, errors: 0) 251 | bus 1, temp: 27.2500 (i: 870000, errors: 0) 252 | 0.7 billion iterations 253 | bus 0, temp: 27.4375 (i: 880000, errors: 0) 254 | bus 1, temp: 27.3125 (i: 880000, errors: 0) 255 | bus 0, temp: 27.3750 (i: 890000, errors: 0) 256 | bus 1, temp: 27.3750 (i: 890000, errors: 0) 257 | bus 0, temp: 27.3750 (i: 900000, errors: 0) 258 | bus 1, temp: 27.3125 (i: 900000, errors: 0) 259 | bus 0, temp: 27.3750 (i: 910000, errors: 0) 260 | bus 1, temp: 27.3125 (i: 910000, errors: 0) 261 | bus 0, temp: 27.3750 (i: 920000, errors: 0) 262 | bus 1, temp: 27.3125 (i: 920000, errors: 0) 263 | bus 0, temp: 27.3750 (i: 930000, errors: 0) 264 | bus 1, temp: 27.3125 (i: 930000, errors: 0) 265 | bus 0, temp: 27.3750 (i: 940000, errors: 0) 266 | bus 1, temp: 27.3125 (i: 940000, errors: 0) 267 | bus 0, temp: 27.4375 (i: 950000, errors: 0) 268 | bus 1, temp: 27.3125 (i: 950000, errors: 0) 269 | bus 0, temp: 27.4375 (i: 960000, errors: 0) 270 | bus 1, temp: 27.3125 (i: 960000, errors: 0) 271 | bus 0, temp: 27.4375 (i: 970000, errors: 0) 272 | bus 1, temp: 27.3125 (i: 970000, errors: 0) 273 | bus 0, temp: 27.4375 (i: 980000, errors: 0) 274 | bus 1, temp: 27.3125 (i: 980000, errors: 0) 275 | bus 0, temp: 27.3750 (i: 990000, errors: 0) 276 | bus 1, temp: 27.2500 (i: 990000, errors: 0) 277 | 0.8 billion iterations 278 | bus 0, temp: 27.3750 (i: 1000000, errors: 0) 279 | bus 1, temp: 27.3125 (i: 1000000, errors: 0) 280 | bus 0, temp: 27.4375 (i: 1010000, errors: 0) 281 | bus 1, temp: 27.3125 (i: 1010000, errors: 0) 282 | bus 0, temp: 27.3750 (i: 1020000, errors: 0) 283 | bus 1, temp: 27.3125 (i: 1020000, errors: 0) 284 | bus 0, temp: 27.3750 (i: 1030000, errors: 0) 285 | bus 1, temp: 27.3125 (i: 1030000, errors: 0) 286 | bus 0, temp: 27.3750 (i: 1040000, errors: 0) 287 | bus 1, temp: 27.3125 (i: 1040000, errors: 0) 288 | bus 0, temp: 27.4375 (i: 1050000, errors: 0) 289 | bus 1, temp: 27.3125 (i: 1050000, errors: 0) 290 | bus 0, temp: 27.3750 (i: 1060000, errors: 0) 291 | bus 1, temp: 27.3125 (i: 1060000, errors: 0) 292 | bus 0, temp: 27.3750 (i: 1070000, errors: 0) 293 | bus 1, temp: 27.3125 (i: 1070000, errors: 0) 294 | bus 0, temp: 27.4375 (i: 1080000, errors: 0) 295 | bus 1, temp: 27.3125 (i: 1080000, errors: 0) 296 | bus 0, temp: 27.3750 (i: 1090000, errors: 0) 297 | bus 1, temp: 27.3125 (i: 1090000, errors: 0) 298 | bus 0, temp: 27.3750 (i: 1100000, errors: 0) 299 | bus 1, temp: 27.3125 (i: 1100000, errors: 0) 300 | bus 0, temp: 27.4375 (i: 1110000, errors: 0) 301 | bus 1, temp: 27.3750 (i: 1110000, errors: 0) 302 | bus 0, temp: 27.3750 (i: 1120000, errors: 0) 303 | bus 1, temp: 27.3125 (i: 1120000, errors: 0) 304 | 0.9 billion iterations 305 | bus 0, temp: 27.4375 (i: 1130000, errors: 0) 306 | bus 1, temp: 27.3125 (i: 1130000, errors: 0) 307 | bus 0, temp: 27.3750 (i: 1140000, errors: 0) 308 | ... 309 | ``` 310 | 311 | -------------------------------------------------------------------------------- /examples/mcp9808_x2_max_speed/main.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "task.h" 3 | #include "pico/stdlib.h" 4 | #include "i2c_dma.h" 5 | #include "mprintf.h" 6 | 7 | static const uint8_t MCP9808_ADDR = 0x18; 8 | static const uint8_t MCP9808_TEMP_REG = 0x05; 9 | 10 | // After power-up the MCP9808 typically requires 250 ms to perform the first 11 | // conversion at the power-up default resolution. See datasheet. 12 | static const int32_t MCP9808_POWER_UP_DELAY_MS = 300; 13 | 14 | static void blink_led_task(void *args) { 15 | (void) args; 16 | 17 | gpio_init(PICO_DEFAULT_LED_PIN); 18 | gpio_set_dir(PICO_DEFAULT_LED_PIN, 1); 19 | gpio_put(PICO_DEFAULT_LED_PIN, !PICO_DEFAULT_LED_PIN_INVERTED); 20 | 21 | while (true) { 22 | gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); 23 | vTaskDelay(pdMS_TO_TICKS(500)); 24 | } 25 | } 26 | 27 | static double mcp9808_raw_temp_to_celsius(uint16_t raw_temp) { 28 | return (raw_temp & 0x0fff) / 16.0 - (raw_temp & 0x1000 ? 256 : 0); 29 | } 30 | 31 | static void mcp9808_bus0_task(void *args) { 32 | i2c_dma_t *i2c_dma = (i2c_dma_t *) args; 33 | 34 | vTaskDelay(pdMS_TO_TICKS(MCP9808_POWER_UP_DELAY_MS)); 35 | 36 | for (int err_cnt = 0, i = 0; true; i += 1) { 37 | uint16_t raw_temp; 38 | const int rc = i2c_dma_read_word_swapped( 39 | i2c_dma, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp 40 | ); 41 | 42 | if (rc != PICO_OK) { 43 | err_cnt += 1; 44 | mprintf("bus 0, error (i: %d, rc: %d, errors: %d)\n", i, rc, err_cnt); 45 | } else if (i % 10000 == 0) { 46 | const double celsius = mcp9808_raw_temp_to_celsius(raw_temp); 47 | mprintf("bus 0, temp: %.4f (i: %d, errors: %d)\n", celsius, i, err_cnt); 48 | } 49 | } 50 | } 51 | 52 | static void mcp9808_bus1_task(void *args) { 53 | i2c_dma_t *i2c_dma = (i2c_dma_t *) args; 54 | 55 | vTaskDelay(pdMS_TO_TICKS(MCP9808_POWER_UP_DELAY_MS)); 56 | 57 | for (int err_cnt = 0, i = 0; true; i += 1) { 58 | uint16_t raw_temp; 59 | const int rc = i2c_dma_read_word_swapped( 60 | i2c_dma, MCP9808_ADDR, MCP9808_TEMP_REG, &raw_temp 61 | ); 62 | 63 | if (rc != PICO_OK) { 64 | err_cnt += 1; 65 | mprintf("bus 1, error (i: %d, rc: %d, errors: %d)\n", i, rc, err_cnt); 66 | } else if (i % 10000 == 0) { 67 | const double celsius = mcp9808_raw_temp_to_celsius(raw_temp); 68 | mprintf("bus 1, temp: %.4f (i: %d, errors: %d)\n", celsius, i, err_cnt); 69 | } 70 | } 71 | } 72 | 73 | static void waste_time_task(void *args) { 74 | (void) args; 75 | 76 | double billion_iterations = 0; 77 | 78 | while (true) { 79 | for (int j = 0; j != 100 * 1000 * 1000; j += 1) { 80 | __asm__("nop"); 81 | } 82 | 83 | billion_iterations += 0.1; 84 | 85 | mprintf("%.1f billion iterations\n", billion_iterations); 86 | } 87 | } 88 | 89 | int main(void) { 90 | stdio_init_all(); 91 | 92 | static i2c_dma_t *i2c0_dma; 93 | int rc = i2c_dma_init(&i2c0_dma, i2c0, (1000 * 1000), 4, 5); 94 | if (rc != PICO_OK) { 95 | mprintf("can't configure I2C0\n"); 96 | return rc; 97 | } 98 | 99 | static i2c_dma_t *i2c1_dma; 100 | rc = i2c_dma_init(&i2c1_dma, i2c1, (1000 * 1000), 6, 7); 101 | if (rc != PICO_OK) { 102 | mprintf("can't configure I2C1\n"); 103 | return rc; 104 | } 105 | 106 | xTaskCreate( 107 | blink_led_task, 108 | "blink-led-task", 109 | configMINIMAL_STACK_SIZE, 110 | NULL, 111 | configMAX_PRIORITIES - 2, 112 | NULL 113 | ); 114 | 115 | xTaskCreate( 116 | mcp9808_bus0_task, 117 | "mcp9808-bus0-task", 118 | configMINIMAL_STACK_SIZE, 119 | i2c0_dma, 120 | configMAX_PRIORITIES - 2, 121 | NULL 122 | ); 123 | 124 | xTaskCreate( 125 | mcp9808_bus1_task, 126 | "mcp9808-bus1-task", 127 | configMINIMAL_STACK_SIZE, 128 | i2c1_dma, 129 | configMAX_PRIORITIES - 2, 130 | NULL 131 | ); 132 | 133 | xTaskCreate( 134 | waste_time_task, 135 | "waste-time-task", 136 | configMINIMAL_STACK_SIZE, 137 | NULL, 138 | configMAX_PRIORITIES - 4, 139 | NULL 140 | ); 141 | 142 | vTaskStartScheduler(); 143 | } 144 | 145 | -------------------------------------------------------------------------------- /examples/ssd1306_bouncing_ball/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(ssd1306_bouncing_ball 2 | main.c 3 | ) 4 | 5 | # Required for ugui library to find ugui_config.h in current directory. 6 | target_include_directories(ssd1306_bouncing_ball PRIVATE 7 | ${CMAKE_CURRENT_LIST_DIR} 8 | ) 9 | 10 | target_link_libraries(ssd1306_bouncing_ball 11 | FreeRTOS-Kernel 12 | FreeRTOS-Kernel-Heap1 13 | pico_stdlib 14 | i2c_dma 15 | common 16 | ugui 17 | ) 18 | 19 | pico_enable_stdio_usb(ssd1306_bouncing_ball 0) 20 | pico_enable_stdio_uart(ssd1306_bouncing_ball 1) 21 | 22 | pico_add_extra_outputs(ssd1306_bouncing_ball) 23 | 24 | -------------------------------------------------------------------------------- /examples/ssd1306_bouncing_ball/README.md: -------------------------------------------------------------------------------- 1 | # ssd1306_bouncing_ball 2 | 3 | This example demonstrates how use a 128x64 pixel SSD1306 OLED display with the 4 | [µGUI graphic library](https://github.com/achimdoebler/UGUI). 5 | 6 | The example continuously performs the following actions: 7 | - Displays a 1-line message at the top of the display 8 | - Draws a horizontal line below the 1-line message 9 | - Moves a ball up, down, left and right in the area below the horizontal line 10 | 11 | The 128x64 pixel SSD1306 OLED display is assumed to be at address 0x3c on I2C0 12 | (GP4 and GP5). 13 | 14 | -------------------------------------------------------------------------------- /examples/ssd1306_bouncing_ball/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "FreeRTOS.h" 3 | #include "task.h" 4 | #include "pico/stdlib.h" 5 | #include "i2c_dma.h" 6 | #include "mprintf.h" 7 | #include "ugui.h" 8 | 9 | #define SSD1306_ADDR 0x3c 10 | #define SSD1306_BYTES_PER_PAGE 128 11 | 12 | #define DISPLAY_WIDTH 128 13 | #define DISPLAY_HEIGHT 64 14 | 15 | #define MAX_X (DISPLAY_WIDTH - 1) 16 | #define MAX_Y (DISPLAY_HEIGHT - 1) 17 | 18 | static uint8_t ssd1306_i2c_message[1 + (DISPLAY_WIDTH * DISPLAY_HEIGHT / 8)]; 19 | static uint8_t *ssd1306_pixel_buffer = &ssd1306_i2c_message[1]; 20 | static UG_GUI gui; 21 | 22 | typedef enum { 23 | // Fundamental commands 24 | 25 | SET_CONTRAST = 0x81, // Double byte command to select 1 out of 26 | // 256 contrast steps. 27 | SET_ENTIRE_DISP_ON = 0xa4, // Bit0 = 0: Output follows RAM content. 28 | // Bit0 = 1: Output ignores RAM content, 29 | // all pixels are turned on. 30 | SET_NORMAL_INVERTED = 0xa6, // Bit0 = 0: Normal display. 31 | // Bit0 = 1: Inverted display. 32 | SET_DISP_ON_OFF = 0xae, // Bit0 = 0: Display off, sleep mode. 33 | // Bit0 = 1: Display on, normal mode. 34 | 35 | // Addressing setting Commands 36 | 37 | SET_ADDRESSING_MODE = 0x20, // Double byte command to set memory 38 | // addressing mode. 39 | SET_COLUMN_ADDRESS = 0x21, // Tripple byte command to setup column start 40 | // and end address. 41 | SET_PAGE_ADDRESS = 0x22, // Tripple byte command to setup page start and 42 | // end address. 43 | 44 | // Hardware configuration (panel resolution and layout related) commands 45 | 46 | SET_DISP_START_LINE = 0x40, // Set display RAM display start line 47 | // register. Valid values are 0 to 63. 48 | SET_SEGMENT_REMAP = 0xa0, // Bit 0 = 0: Map col addr 0 to SEG0. 49 | // Bit 0 = 1: Map col addr 127 to SEG0. 50 | SET_MUX_RATIO = 0xa8, // Double byte command to configure display 51 | // height. Valid height values are 15 to 63. 52 | SET_COM_OUTPUT_DIR = 0xc0, // Bit 3 = 0: Scan from 0 to N-1. 53 | // Bit 3 = 1: Scan from N-1 to 0. (N=height) 54 | SET_DISP_OFFSET = 0xd3, // Double byte command to configure vertical 55 | // display shift. Valid values are 0 to 63. 56 | SET_COM_PINS_CONFIG = 0xda, // Double byte command to set COM pins 57 | // hardware configuration. 58 | 59 | // Timing and driving scheme setting commands 60 | 61 | SET_DCLK_FOSC = 0xd5, // Double byte command to set display clock 62 | // divide ratio and oscillator frequency. 63 | SET_PRECHARGE_PERIOD = 0xd9, // Double byte command to set pre-charge 64 | // period. 65 | SET_VCOM_DESEL_LEVEL = 0xdb, // Double byte command to set VCOMH deselect 66 | // level. 67 | 68 | // Charge pump command 69 | 70 | SET_CHARGE_PUMP = 0x8d, // Double byte command to enable/disable 71 | // charge pump. 72 | // Byte2 = 0x10: Disable charge pump. 73 | // Byte2 = 0x14: Enable charge pump. 74 | } ssd1306_command_t; 75 | 76 | static int ssd1306_send_command(i2c_dma_t *i2c_dma, uint8_t byte) { 77 | return i2c_dma_write_byte(i2c_dma, SSD1306_ADDR, 0x80, byte); 78 | } 79 | 80 | static void ssd1306_init(i2c_dma_t *i2c_dma) { 81 | const uint8_t commands[] = { 82 | SET_DISP_ON_OFF | 0x00, // Display off. 83 | SET_DCLK_FOSC, 0x80, // Set clock divide ratio and oscillator 84 | // frequency. 85 | SET_MUX_RATIO, 0x3f, // Set display height. 86 | SET_DISP_OFFSET, 0x00, // Set vertical display shift to 0. 87 | SET_DISP_START_LINE, // Set display RAM display start line 88 | // register to 0. 89 | SET_CHARGE_PUMP, 0x14, // Enable charge pump. 90 | SET_SEGMENT_REMAP | 0x01, // Map col addr 127 to SEG0. 91 | SET_COM_OUTPUT_DIR | 0x08, // Scan from N-1 to 0. (N=height) 92 | SET_COM_PINS_CONFIG, 0x12, // Set COM pins hardware configuration to 93 | // 0x12. 94 | SET_CONTRAST, 0xcf, // Set contrast to 0xcf 95 | SET_PRECHARGE_PERIOD, 0xf1, // Set pre-charge to 0xf1 96 | SET_VCOM_DESEL_LEVEL, 0x40, // Set VCOMH deselect to 0x40 97 | SET_ENTIRE_DISP_ON, // Output follows RAM content. 98 | SET_NORMAL_INVERTED | 0x00, // Normal display. 99 | SET_ADDRESSING_MODE, 0x00, // Set addressing mode to horizontal mode. 100 | SET_COLUMN_ADDRESS, 0x00, 0x7f, // Set column start and end address. 101 | SET_PAGE_ADDRESS, 0x00, 0x07, // Set page start and end address. 102 | SET_DISP_ON_OFF | 0x01, // Display on. 103 | }; 104 | 105 | for(int i = 0; i < sizeof(commands); i++) { 106 | ssd1306_send_command(i2c_dma, commands[i]); 107 | } 108 | 109 | ssd1306_i2c_message[0] = 0x40; 110 | } 111 | 112 | static void ssd1306_update(i2c_dma_t *i2c_dma) { 113 | i2c_dma_write( 114 | i2c_dma, SSD1306_ADDR, ssd1306_i2c_message, sizeof(ssd1306_i2c_message) 115 | ); 116 | } 117 | 118 | static void ugui_draw_pixel_callback(UG_S16 x, UG_S16 y, UG_COLOR color) { 119 | if (x < 0 || x > MAX_X || y < 0 || y > MAX_Y) 120 | return; 121 | 122 | const uint8_t page_number = y / 8; 123 | const uint8_t column_number = x; 124 | uint8_t *byte = &ssd1306_pixel_buffer[ 125 | page_number * SSD1306_BYTES_PER_PAGE + column_number 126 | ]; 127 | 128 | const uint8_t bit_number = y % 8; 129 | const uint8_t bit_mask = 1 << bit_number; 130 | 131 | switch (color) { 132 | case C_BLACK: 133 | *byte &= ~bit_mask; // Black -> clear pixel. 134 | break; 135 | case C_WHITE: 136 | *byte |= bit_mask; // White -> set pixel. 137 | break; 138 | default: 139 | *byte ^= bit_mask; // Any other color -> invert pixel. 140 | } 141 | } 142 | 143 | static void ugui_init() { 144 | UG_Init(&gui, ugui_draw_pixel_callback, DISPLAY_WIDTH, DISPLAY_HEIGHT); 145 | UG_SetBackcolor(C_BLACK); 146 | UG_SetForecolor(C_WHITE); 147 | UG_FillScreen(C_BLACK); 148 | } 149 | 150 | static void blink_led_task(void *args) { 151 | (void) args; 152 | 153 | gpio_init(PICO_DEFAULT_LED_PIN); 154 | gpio_set_dir(PICO_DEFAULT_LED_PIN, 1); 155 | gpio_put(PICO_DEFAULT_LED_PIN, !PICO_DEFAULT_LED_PIN_INVERTED); 156 | 157 | while (true) { 158 | gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); 159 | vTaskDelay(pdMS_TO_TICKS(500)); 160 | } 161 | } 162 | 163 | static void ssd1306_bouncing_ball_task(void *args) { 164 | i2c_dma_t *i2c_dma = (i2c_dma_t *) args; 165 | 166 | ssd1306_init(i2c_dma); 167 | ugui_init(); 168 | 169 | // Start position of ball is the top left just below the horizontal line. 170 | const UG_S16 ball_radius = 8; 171 | UG_S16 ball_x = 7; 172 | UG_S16 ball_y = 21; 173 | UG_S16 x_inc = 1; // 1: move right, -1: move left 174 | UG_S16 y_inc = 1; // 1: move down, -1: move up 175 | 176 | const UG_FONT *font = &FONT_5X12; 177 | UG_FontSelect(font); 178 | 179 | for (int i = 0; true; i += 1) { 180 | // Clear the display. 181 | UG_FillScreen(C_BLACK); 182 | 183 | // Print a message at the top left of the display. 184 | char message[20]; 185 | sprintf(message, "%d", i + 1); 186 | UG_PutString(0, 0, message); 187 | 188 | // Draw a horizontal line below the message. 189 | // The ball bounces in the area below the horizontal line. 190 | const UG_S16 H_LINE_Y = font->char_height + 1; 191 | UG_DrawLine(0, H_LINE_Y, MAX_X, H_LINE_Y, C_WHITE); 192 | 193 | // If the ball has bounced off the left or right, update x_inc. 194 | if (ball_x - ball_radius <= 0) { 195 | // Ball bounced off left, begin moving right. 196 | x_inc = 1; 197 | } else if (ball_x + ball_radius >= MAX_X) { 198 | // Ball bounced off right, begin moving left. 199 | x_inc = -1; 200 | } 201 | 202 | // If the ball has bounced off the top or bottom, update y_inc. 203 | if (ball_y - ball_radius <= H_LINE_Y + 1) { 204 | // Ball bounced off top, begin moving down. 205 | y_inc = 1; 206 | } else if (ball_y + ball_radius >= MAX_Y) { 207 | // Ball bounced off bottom, begin moving up. 208 | y_inc = -1; 209 | } 210 | 211 | // Move the ball one pixel left or right, and up or down. 212 | ball_x += x_inc; 213 | ball_y += y_inc; 214 | 215 | // Draw the ball. 216 | UG_DrawCircle(ball_x, ball_y, ball_radius, C_WHITE); 217 | 218 | // Send all pixels to the SSD1306. 219 | ssd1306_update(i2c_dma); 220 | } 221 | } 222 | 223 | int main(void) { 224 | stdio_init_all(); 225 | 226 | i2c_dma_t *i2c0_dma; 227 | const int rc = i2c_dma_init(&i2c0_dma, i2c0, 1000000, 4, 5); 228 | if (rc != PICO_OK) { 229 | mprintf("can't configure I2C0\n"); 230 | return rc; 231 | } 232 | 233 | xTaskCreate( 234 | blink_led_task, 235 | "blink-led-task", 236 | configMINIMAL_STACK_SIZE, 237 | NULL, 238 | configMAX_PRIORITIES - 2, 239 | NULL 240 | ); 241 | 242 | xTaskCreate( 243 | ssd1306_bouncing_ball_task, 244 | "ssd1306-bouncing-ball-task", 245 | configMINIMAL_STACK_SIZE, 246 | i2c0_dma, 247 | configMAX_PRIORITIES - 2, 248 | NULL 249 | ); 250 | 251 | vTaskStartScheduler(); 252 | } 253 | 254 | -------------------------------------------------------------------------------- /examples/ssd1306_bouncing_ball/ugui_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __UGUI_CONFIG_H 2 | #define __UGUI_CONFIG_H 3 | 4 | #include 5 | 6 | /* -------------------------------------------------------------------------------- */ 7 | /* -- CONFIG SECTION -- */ 8 | /* -------------------------------------------------------------------------------- */ 9 | 10 | //#define USE_MULTITASKING 11 | 12 | /* Enable color mode */ 13 | //#define USE_COLOR_RGB888 // RGB = 0xFF,0xFF,0xFF 14 | #define USE_COLOR_RGB565 // RGB = 0bRRRRRGGGGGGBBBBB 15 | 16 | /* Enable needed fonts here */ 17 | //#define USE_FONT_4X6 18 | //#define USE_FONT_5X8 19 | #define USE_FONT_5X12 20 | //#define USE_FONT_6X8 21 | //#define USE_FONT_6X10 22 | //#define USE_FONT_7X12 23 | //#define USE_FONT_8X8 24 | //#define USE_FONT_8X12_CYRILLIC 25 | //#define USE_FONT_8X12 26 | //#define USE_FONT_8X12 27 | //#define USE_FONT_8X14 28 | //#define USE_FONT_10X16 29 | //#define USE_FONT_12X16 30 | //#define USE_FONT_12X20 31 | //#define USE_FONT_16X26 32 | //#define USE_FONT_22X36 33 | //#define USE_FONT_24X40 34 | //#define USE_FONT_32X53 35 | 36 | /* Specify platform-dependent integer types here */ 37 | 38 | #define __UG_FONT_DATA const 39 | typedef uint8_t UG_U8; 40 | typedef int8_t UG_S8; 41 | typedef uint16_t UG_U16; 42 | typedef int16_t UG_S16; 43 | typedef uint32_t UG_U32; 44 | typedef int32_t UG_S32; 45 | 46 | 47 | /* Example for dsPIC33 48 | typedef unsigned char UG_U8; 49 | typedef signed char UG_S8; 50 | typedef unsigned int UG_U16; 51 | typedef signed int UG_S16; 52 | typedef unsigned long int UG_U32; 53 | typedef signed long int UG_S32; 54 | */ 55 | 56 | /* -------------------------------------------------------------------------------- */ 57 | /* -------------------------------------------------------------------------------- */ 58 | 59 | 60 | /* Feature enablers */ 61 | #define USE_PRERENDER_EVENT 62 | #define USE_POSTRENDER_EVENT 63 | 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /notes.txt: -------------------------------------------------------------------------------- 1 | // TODO 2 | // - A test where the highest priority task doesn't used the I2C busses. 3 | // Perhaps this task would show that I2C_TRANSFER_TIMEOUT_MS, currently at 4 | // 10ms, is too low? 5 | // - There is i2c_dma_config but no corresponding i2c_dma_deconfig. 6 | // - Test with the I2C-LCD that can block the bus. 7 | // 8 | // Ideas 9 | // - Improve freertos_hooks.c. 10 | // - Make timeout configurable or a parameter? The value could be stored in 11 | // i2c_dma_t and the default value could be I2C_TIMEOUT_MS. Functions could 12 | // be provided for getting and setting its value. 13 | 14 | https://docs.kernel.org/i2c/smbus-protocol.html 15 | 16 | static uint16_t celsius_to_mcp9808_raw_temp(double celsius) { 17 | if (celsius < -256) { 18 | celsius = -256; 19 | } else if (celsius > 255.75) { 20 | celsius = 255.75; 21 | } 22 | 23 | double raw_celsius = celsius < 0 ? celsius + 256 : celsius; 24 | uint16_t raw_temp = lround(raw_celsius * 4) << 2; 25 | 26 | if (raw_temp == 0x1000 && celsius >= -1 && celsius < 0) { 27 | // Negative celsius values close to 0 are rounded to 0 meaning they are no 28 | // longer negative. 29 | raw_temp = 0; 30 | } else if (celsius < 0) { 31 | raw_temp |= 0x1000; 32 | } 33 | 34 | return raw_temp; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | # GIT_SUBMODULES_RECURSE was added in 3.17 33 | if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") 34 | FetchContent_Declare( 35 | pico_sdk 36 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 37 | GIT_TAG master 38 | GIT_SUBMODULES_RECURSE FALSE 39 | ) 40 | else () 41 | FetchContent_Declare( 42 | pico_sdk 43 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 44 | GIT_TAG master 45 | ) 46 | endif () 47 | 48 | if (NOT pico_sdk) 49 | message("Downloading Raspberry Pi Pico SDK") 50 | FetchContent_Populate(pico_sdk) 51 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 52 | endif () 53 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 54 | else () 55 | message(FATAL_ERROR 56 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 57 | ) 58 | endif () 59 | endif () 60 | 61 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 62 | if (NOT EXISTS ${PICO_SDK_PATH}) 63 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 64 | endif () 65 | 66 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 67 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 68 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 69 | endif () 70 | 71 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 72 | 73 | include(${PICO_SDK_INIT_CMAKE_FILE}) 74 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(i2c_dma INTERFACE) 2 | 3 | target_include_directories(i2c_dma INTERFACE 4 | ${CMAKE_CURRENT_LIST_DIR}/include 5 | ) 6 | 7 | target_sources(i2c_dma INTERFACE 8 | ${CMAKE_CURRENT_LIST_DIR}/i2c_dma.c 9 | ) 10 | 11 | target_link_libraries(i2c_dma INTERFACE 12 | FreeRTOS-Kernel 13 | pico_stdlib 14 | hardware_dma 15 | hardware_i2c 16 | ) 17 | 18 | -------------------------------------------------------------------------------- /src/i2c_dma.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "semphr.h" 3 | #include "hardware/clocks.h" 4 | #include "hardware/dma.h" 5 | #include "hardware/gpio.h" 6 | #include "hardware/irq.h" 7 | #include "i2c_dma.h" 8 | 9 | #define I2C_MAX_TRANSFER_SIZE 1056 10 | // A transfer timeout of 1000ms will allow a 10000 bit transfer to complete 11 | // successfully without timeouts at baudrates as low as 10000 baud. 12 | #define I2C_TRANSFER_TIMEOUT_MS 1000 13 | #define I2C_TAKE_MUTEX_TIMEOUT_MS 10000 14 | 15 | typedef struct i2c_dma_s { 16 | i2c_inst_t *i2c; 17 | 18 | uint irq_num; 19 | irq_handler_t irq_handler; 20 | 21 | uint baudrate; 22 | uint sda_gpio; 23 | uint scl_gpio; 24 | 25 | SemaphoreHandle_t semaphore; 26 | SemaphoreHandle_t mutex; 27 | 28 | volatile bool stop_detected; 29 | volatile bool abort_detected; 30 | 31 | uint16_t data_cmds[I2C_MAX_TRANSFER_SIZE]; 32 | } i2c_dma_t; 33 | 34 | static i2c_dma_t i2c_dma_list[2]; 35 | 36 | static void i2c_dma_irq_handler(i2c_dma_t *i2c_dma) { 37 | const uint32_t status = i2c_get_hw(i2c_dma->i2c)->intr_stat; 38 | 39 | // If there is an abort, normally there is an abort interrupt followed by a 40 | // stop interrupt. On the rare occasion, for example, if the first I2C 41 | // transaction after reset is aborted, the abort and stop interrupt flags 42 | // appear to be set at the same instant or almost the same instant. 43 | if (status & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) { 44 | // Transfer aborted. 45 | i2c_get_hw(i2c_dma->i2c)->clr_tx_abrt; 46 | i2c_dma->abort_detected = true; 47 | } 48 | 49 | if (status & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { 50 | // Transfer complete. 51 | i2c_get_hw(i2c_dma->i2c)->clr_stop_det; 52 | i2c_dma->stop_detected = true; 53 | 54 | // If xSemaphoreGiveFromISR fails and returns errQUEUE_FULL the error 55 | // isn't handled here. There isn't much that can be done. If 56 | // xSemaphoreGiveFromISR fails, the corresponding call to xSemaphoreTake 57 | // will eventually timeout. 58 | BaseType_t task_switch_required = pdFALSE; 59 | xSemaphoreGiveFromISR(i2c_dma->semaphore, &task_switch_required); 60 | portYIELD_FROM_ISR(task_switch_required); 61 | } 62 | } 63 | 64 | static void i2c0_dma_irq_handler(void) { 65 | i2c_dma_irq_handler(&i2c_dma_list[0]); 66 | } 67 | 68 | static void i2c1_dma_irq_handler(void) { 69 | i2c_dma_irq_handler(&i2c_dma_list[1]); 70 | } 71 | 72 | static void i2c_dma_set_target_addr(i2c_inst_t *i2c, uint8_t addr) { 73 | i2c_get_hw(i2c)->enable = 0; 74 | i2c_get_hw(i2c)->tar = addr; 75 | i2c_get_hw(i2c)->enable = 1; 76 | } 77 | 78 | static void i2c_dma_tx_channel_configure( 79 | i2c_inst_t *i2c, int tx_channel, const uint16_t *tx_buf, size_t len 80 | ) { 81 | dma_channel_config tx_config = dma_channel_get_default_config(tx_channel); 82 | channel_config_set_read_increment(&tx_config, true); 83 | channel_config_set_write_increment(&tx_config, false); 84 | channel_config_set_transfer_data_size(&tx_config, DMA_SIZE_16); 85 | channel_config_set_dreq(&tx_config, i2c_get_dreq(i2c, true)); 86 | dma_channel_configure( 87 | tx_channel, &tx_config, &i2c_get_hw(i2c)->data_cmd, tx_buf, len, true 88 | ); 89 | } 90 | 91 | static void i2c_dma_rx_channel_configure( 92 | i2c_inst_t *i2c, int rx_channel, uint8_t *rx_buf, size_t len 93 | ) { 94 | dma_channel_config rx_config = dma_channel_get_default_config(rx_channel); 95 | channel_config_set_read_increment(&rx_config, false); 96 | channel_config_set_write_increment(&rx_config, true); 97 | channel_config_set_transfer_data_size(&rx_config, DMA_SIZE_8); 98 | channel_config_set_dreq(&rx_config, i2c_get_dreq(i2c, false)); 99 | dma_channel_configure( 100 | rx_channel, &rx_config, rx_buf, &i2c_get_hw(i2c)->data_cmd, len, true 101 | ); 102 | } 103 | 104 | static void i2c_dma_pin_open_drain(uint gpio) { 105 | gpio_set_function(gpio, GPIO_FUNC_SIO); 106 | gpio_set_dir(gpio, GPIO_IN); 107 | gpio_put(gpio, 0); 108 | } 109 | 110 | static void i2c_dma_pin_od_low(uint gpio) { 111 | gpio_set_dir(gpio, GPIO_OUT); 112 | } 113 | 114 | static void i2c_dma_pin_od_high(uint gpio) { 115 | gpio_set_dir(gpio, GPIO_IN); 116 | } 117 | 118 | static void i2c_dma_unblock(i2c_dma_t *i2c_dma) { 119 | i2c_dma_pin_open_drain(i2c_dma->sda_gpio); 120 | i2c_dma_pin_open_drain(i2c_dma->scl_gpio); 121 | 122 | bool sda_high; 123 | int max_tries = 9; 124 | 125 | // Make sure the frequency of the bit-bannged I2C clock is at most 100KHz. 126 | const uint32_t f_clk_sys_khz = 127 | frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS); 128 | const uint32_t i2c_delay = f_clk_sys_khz / 100 / 2; 129 | 130 | do { 131 | i2c_dma_pin_od_low(i2c_dma->scl_gpio); 132 | for (int i = i2c_delay; i > 0; i -= 1) { 133 | __asm__("nop"); 134 | } 135 | 136 | i2c_dma_pin_od_high(i2c_dma->scl_gpio); 137 | for (int i = i2c_delay; i > 0; i -= 1) { 138 | __asm__("nop"); 139 | } 140 | 141 | max_tries -= 1; 142 | sda_high = gpio_get(i2c_dma->sda_gpio); 143 | } while (!sda_high && max_tries > 0); 144 | } 145 | 146 | static bool i2c_dma_is_blocked(i2c_dma_t *i2c_dma) { 147 | i2c_dma_pin_open_drain(i2c_dma->sda_gpio); 148 | i2c_dma_pin_open_drain(i2c_dma->scl_gpio); 149 | 150 | const bool sda_high = gpio_get(i2c_dma->sda_gpio); 151 | const bool scl_high = gpio_get(i2c_dma->scl_gpio); 152 | 153 | return !sda_high || !scl_high; 154 | } 155 | 156 | static int i2c_dma_init_intern(i2c_dma_t *i2c_dma) { 157 | irq_set_enabled(i2c_dma->irq_num, false); 158 | 159 | i2c_dma->stop_detected = false; 160 | i2c_dma->abort_detected = false; 161 | 162 | if (uxSemaphoreGetCount(i2c_dma->semaphore) != 0) { 163 | if (xSemaphoreTake(i2c_dma->semaphore, 0) != pdTRUE) { 164 | return PICO_ERROR_GENERIC; 165 | } 166 | } 167 | 168 | // Don't do anything with i2c_dma->mutex here, let i2c_dma_write_read take 169 | // care of it. Also, directly after creation with xSemaphoreCreateMutex a 170 | // mutex can be successfully taken. 171 | 172 | // Attempt to unblock a blocked bus. If it can't be unblocked, continue 173 | // anyway. 174 | if (i2c_dma_is_blocked(i2c_dma)) { 175 | i2c_dma_unblock(i2c_dma); 176 | } 177 | 178 | i2c_init(i2c_dma->i2c, i2c_dma->baudrate); 179 | 180 | gpio_set_function(i2c_dma->sda_gpio, GPIO_FUNC_I2C); 181 | gpio_set_function(i2c_dma->scl_gpio, GPIO_FUNC_I2C); 182 | gpio_pull_up(i2c_dma->sda_gpio); 183 | gpio_pull_up(i2c_dma->scl_gpio); 184 | 185 | i2c_get_hw(i2c_dma->i2c)->intr_mask = 186 | I2C_IC_INTR_MASK_M_STOP_DET_BITS | 187 | I2C_IC_INTR_MASK_M_TX_ABRT_BITS; 188 | 189 | irq_set_exclusive_handler(i2c_dma->irq_num, i2c_dma->irq_handler); 190 | irq_set_enabled(i2c_dma->irq_num, true); 191 | 192 | return PICO_OK; 193 | } 194 | 195 | static int i2c_dma_reinit(i2c_dma_t *i2c_dma) { 196 | return i2c_dma_init_intern(i2c_dma); 197 | } 198 | 199 | int i2c_dma_init( 200 | i2c_dma_t **pi2c_dma, 201 | i2c_inst_t *i2c, 202 | uint baudrate, 203 | uint sda_gpio, 204 | uint scl_gpio 205 | ) { 206 | i2c_dma_t *i2c_dma; 207 | 208 | if (i2c == i2c0) { 209 | i2c_dma = &i2c_dma_list[0]; 210 | i2c_dma->i2c = i2c0; 211 | i2c_dma->irq_num = I2C0_IRQ; 212 | i2c_dma->irq_handler = i2c0_dma_irq_handler; 213 | } else { 214 | i2c_dma = &i2c_dma_list[1]; 215 | i2c_dma->i2c = i2c1; 216 | i2c_dma->irq_num = I2C1_IRQ; 217 | i2c_dma->irq_handler = i2c1_dma_irq_handler; 218 | } 219 | 220 | *pi2c_dma = i2c_dma; 221 | 222 | i2c_dma->baudrate = baudrate; 223 | i2c_dma->sda_gpio = sda_gpio; 224 | i2c_dma->scl_gpio = scl_gpio; 225 | 226 | i2c_dma->semaphore = xSemaphoreCreateBinary(); 227 | if (i2c_dma->semaphore == NULL) { 228 | return PICO_ERROR_GENERIC; 229 | } 230 | 231 | i2c_dma->mutex = xSemaphoreCreateMutex(); 232 | if (i2c_dma->mutex == NULL) { 233 | return PICO_ERROR_GENERIC; 234 | } 235 | 236 | return i2c_dma_init_intern(i2c_dma); 237 | } 238 | 239 | static int i2c_dma_write_read_internal( 240 | i2c_dma_t *i2c_dma, 241 | uint8_t addr, 242 | const uint8_t *wbuf, 243 | size_t wbuf_len, 244 | uint8_t *rbuf, 245 | size_t rbuf_len 246 | ) { 247 | if ( 248 | (wbuf_len > 0 && wbuf == NULL) || 249 | (rbuf_len > 0 && rbuf == NULL) || 250 | (wbuf_len == 0 && rbuf_len == 0) || 251 | (wbuf_len + rbuf_len > I2C_MAX_TRANSFER_SIZE) 252 | ) { 253 | return PICO_ERROR_INVALID_ARG; 254 | } 255 | 256 | const bool writing = (wbuf_len > 0); 257 | const bool reading = (rbuf_len > 0); 258 | 259 | int tx_chan = 0; // Channel for writing data_cmds to I2C peripheral. 260 | int rx_chan = 0; // Channel for reading data from I2C peripheral, if needed. 261 | 262 | if (writing) { 263 | // Setup commands for each byte to write to the I2C bus. 264 | for (size_t i = 0; i != wbuf_len; ++i) { 265 | i2c_dma->data_cmds[i] = wbuf[i]; 266 | } 267 | 268 | // The first byte written must be preceded by a start. 269 | i2c_dma->data_cmds[0] |= I2C_IC_DATA_CMD_RESTART_BITS; 270 | } 271 | 272 | // DMA tx_chan is needed for both writing and reading. 273 | tx_chan = dma_claim_unused_channel(false); 274 | if (tx_chan == -1) { 275 | return PICO_ERROR_GENERIC; 276 | } 277 | 278 | if (reading) { 279 | // Setup commands for each byte to read from the I2C bus. 280 | for (size_t i = 0; i != rbuf_len; ++i) { 281 | i2c_dma->data_cmds[wbuf_len + i] = I2C_IC_DATA_CMD_CMD_BITS; 282 | } 283 | 284 | // The first byte read must be preceded by a start/restart. 285 | i2c_dma->data_cmds[wbuf_len] |= I2C_IC_DATA_CMD_RESTART_BITS; 286 | 287 | // DMA rx_chan is only needed for reading. 288 | rx_chan = dma_claim_unused_channel(false); 289 | if (rx_chan == -1) { 290 | dma_channel_unclaim(tx_chan); 291 | return PICO_ERROR_GENERIC; 292 | } 293 | } 294 | 295 | // The last byte transfered must be followed by a stop. 296 | i2c_dma->data_cmds[wbuf_len + rbuf_len - 1] |= I2C_IC_DATA_CMD_STOP_BITS; 297 | 298 | // Tell the I2C peripheral the adderss of the device for the transfer. 299 | i2c_dma_set_target_addr(i2c_dma->i2c, addr); 300 | 301 | i2c_dma->stop_detected = false; 302 | i2c_dma->abort_detected = false; 303 | 304 | // Start the I2C transfer on required DMA channels. 305 | if (reading) { 306 | i2c_dma_rx_channel_configure(i2c_dma->i2c, rx_chan, rbuf, rbuf_len); 307 | } 308 | i2c_dma_tx_channel_configure( 309 | i2c_dma->i2c, tx_chan, i2c_dma->data_cmds, wbuf_len + rbuf_len 310 | ); 311 | 312 | // The I2C transfer via DMA has been started. Wait for it to complete. Under 313 | // normal circumstances, the transfer is complete when a stop is detected on 314 | // the bus. If the hardware detects problems during the transfer, there will 315 | // normally be an abort followed by a stop. Scenarios where a stop and/or 316 | // abort are not detected are also possible, for these scenarios a timeout 317 | // is needed. As an example, no stop will be detected if SDA gets stuck low. 318 | const bool timeout = xSemaphoreTake( 319 | i2c_dma->semaphore, I2C_TRANSFER_TIMEOUT_MS * portTICK_PERIOD_MS 320 | ) == pdFALSE; 321 | 322 | // If there were problems, abort the DMA. 323 | if (timeout || i2c_dma->abort_detected || !i2c_dma->stop_detected) { 324 | dma_channel_abort(tx_chan); 325 | if (reading) { 326 | dma_channel_abort(rx_chan); 327 | } 328 | } 329 | 330 | // Free the DMA channels. 331 | dma_channel_unclaim(tx_chan); 332 | if (reading) { 333 | dma_channel_unclaim(rx_chan); 334 | } 335 | 336 | int rc = PICO_OK; 337 | 338 | if (timeout) { 339 | rc = PICO_ERROR_TIMEOUT; 340 | } else if (i2c_dma->abort_detected || !i2c_dma->stop_detected) { 341 | rc = PICO_ERROR_IO; 342 | } 343 | 344 | // Attempt to recover from errors. 345 | if (rc != PICO_OK) { 346 | i2c_dma_reinit(i2c_dma); 347 | } 348 | 349 | return rc; 350 | } 351 | 352 | int i2c_dma_write_read( 353 | i2c_dma_t *i2c_dma, 354 | uint8_t addr, 355 | const uint8_t *wbuf, 356 | size_t wbuf_len, 357 | uint8_t *rbuf, 358 | size_t rbuf_len 359 | ) { 360 | if (xSemaphoreTake( 361 | i2c_dma->mutex, I2C_TAKE_MUTEX_TIMEOUT_MS * portTICK_PERIOD_MS 362 | ) != pdTRUE) { 363 | return PICO_ERROR_TIMEOUT; 364 | } 365 | 366 | const int rc = i2c_dma_write_read_internal( 367 | i2c_dma, addr, wbuf, wbuf_len, rbuf, rbuf_len 368 | ); 369 | 370 | if (xSemaphoreGive(i2c_dma->mutex) != pdTRUE && rc == PICO_OK) { 371 | return PICO_ERROR_GENERIC; 372 | } 373 | 374 | return rc; 375 | } 376 | 377 | -------------------------------------------------------------------------------- /src/include/i2c_dma.h: -------------------------------------------------------------------------------- 1 | #ifndef _I2C_DMA_H 2 | #define _I2C_DMA_H 3 | 4 | #include "hardware/i2c.h" 5 | 6 | // Explanation of symbols used in function documentation below. 7 | // --------------+------------------------------------------------------------ 8 | // S | Start condition. 9 | // Sr | Repeated start condition, used to switch from write to read 10 | // | mode. 11 | // P | Stop condition. 12 | // Rd/Wr (1 bit) | Read/Write bit. Rd equals 1, Wr equals 0. 13 | // A, NA (1 bit) | Acknowledge (ACK) and Not Acknowledge (NACK) bit 14 | // addr (7 bits) | 7 bit I2C address. 15 | // reg (8 bits) | Register byte, a data byte which typically selects a 16 | // | register on the device. 17 | // [..] | Data sent by I2C device, as opposed to data sent by the 18 | // | host adapter. 19 | // --------------+------------------------------------------------------------ 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | // An i2c_dma_t stores all the data required by the i2c_dma_* functions 26 | // for driving I2C devices connected to I2C peripherals I2C0 and I2C1. Call 27 | // i2c_dma_init to get a pointer to an i2c_dma_t for I2C0 or I2C1. 28 | typedef struct i2c_dma_s i2c_dma_t; 29 | 30 | // Initializes an I2C peripheral, its SDA pin, its SCL pin, its baudrate, 31 | // enables the peripheral, and prepares it for DMA usage. i2c_dma_init must be 32 | // called before other functions. Copies a pointer to an i2c_dma_t to 33 | // *pi2c_dma. This i2c_dma_t pointer is the pointer passed as the first 34 | // parameter to all other i2c_dma_* functions. 35 | // 36 | // Returns 37 | // PICO_OK 38 | // Function completed successfully 39 | // PICO_ERROR_GENERIC 40 | // Error creating semaphore 41 | // Error creating mutex 42 | // Error attempting to take a semaphore 43 | int i2c_dma_init( 44 | i2c_dma_t **pi2c_dma, // A pointer to an i2c_dma_t pointer 45 | i2c_inst_t *i2c, // Either i2c0 or i2c1 46 | uint baudrate, // Baudrate in hertz 47 | uint sda_gpio, // GPIO number for SDA 48 | uint scl_gpio // GPIO number for SCL 49 | ); 50 | 51 | // Writes a block of bytes and/or reads a block of bytes in a single I2C 52 | // transaction. 53 | // 54 | // I2C Transactions: 55 | // 56 | // Write a block of bytes: 57 | // S addr Wr [A] wbuf(0) [A] wbuf(1) [A] ... [A] wbuf(wbuf_len-1) [A] P 58 | // 59 | // Read a block of bytes: 60 | // S addr Rd [A] [rbuf(0)] A [rbuf(1)] A ... A [rbuf(rbuf_len-1)] NA P 61 | // 62 | // Write a block of bytes and read a block of bytes: 63 | // S addr Wr [A] wbuf(0) [A] wbuf(1) [A] ... [A] wbuf(wbuf_len-1) [A] 64 | // Sr addr Rd [A] [rbuf(0)] A [rbuf(1)] A ... A [rbuf(rbuf_len-1)] NA P 65 | // 66 | // Returns 67 | // PICO_OK 68 | // Function completed successfully 69 | // PICO_ERROR_INVALID_ARG 70 | // Invalid argument passed to function 71 | // PICO_ERROR_TIMEOUT 72 | // Timeout waiting to take a mutex 73 | // Timeout waiting for I2C transaction to complete 74 | // PICO_ERROR_IO 75 | // I2C transaction aborted by I2C peripheral 76 | // No stop condition for transaction detected by I2C peripheral 77 | // PICO_ERROR_GENERIC 78 | // Error attempting to give a mutex 79 | // Error attemptimg to claim a DMA channel 80 | int i2c_dma_write_read( 81 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 82 | uint8_t addr, // 7 bit I2C address 83 | const uint8_t *wbuf, // Pointer to block of bytes to write or NULL 84 | size_t wbuf_len, // Length of block of bytes to write or 0 85 | uint8_t *rbuf, // Pointer to block of bytes for data read or NULL 86 | size_t rbuf_len // Number of bytes of data to read or 0 87 | ); 88 | 89 | // Writes a block of bytes. 90 | // 91 | // I2C Transaction: 92 | // S addr Wr [A] wbuf(0) [A] wbuf(1) [A] ... [A] wbuf(wbuf_len-1) [A] P 93 | // 94 | // Returns 95 | // PICO_OK 96 | // Function completed successfully 97 | // PICO_ERROR_INVALID_ARG 98 | // Invalid argument passed to function 99 | // PICO_ERROR_TIMEOUT 100 | // Timeout waiting to take a mutex 101 | // Timeout waiting for I2C transaction to complete 102 | // PICO_ERROR_IO 103 | // I2C transaction aborted by I2C peripheral 104 | // No stop condition for transaction detected by I2C peripheral 105 | // PICO_ERROR_GENERIC 106 | // Error attempting to give a mutex 107 | // Error attemptimg to claim a DMA channel 108 | static inline int i2c_dma_write( 109 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 110 | uint8_t addr, // 7 bit I2C address 111 | const uint8_t *wbuf, // Pointer to block of bytes to write or NULL 112 | size_t wbuf_len // Length of block of bytes to write or 0 113 | ) { 114 | return i2c_dma_write_read(i2c_dma, addr, wbuf, wbuf_len, NULL, 0); 115 | } 116 | 117 | // Reads a block of bytes. 118 | // 119 | // I2C Transaction: 120 | // S addr Rd [A] [rbuf(0)] A [rbuf(1)] A ... A [rbuf(rbuf_len-1)] NA P 121 | // 122 | // Returns 123 | // PICO_OK 124 | // Function completed successfully 125 | // PICO_ERROR_INVALID_ARG 126 | // Invalid argument passed to function 127 | // PICO_ERROR_TIMEOUT 128 | // Timeout waiting to take a mutex 129 | // Timeout waiting for I2C transaction to complete 130 | // PICO_ERROR_IO 131 | // I2C transaction aborted by I2C peripheral 132 | // No stop condition for transaction detected by I2C peripheral 133 | // PICO_ERROR_GENERIC 134 | // Error attempting to give a mutex 135 | // Error attemptimg to claim a DMA channel 136 | static inline int i2c_dma_read( 137 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 138 | uint8_t addr, // 7 bit I2C address 139 | uint8_t *rbuf, // Pointer to block of bytes for data read or NULL 140 | size_t rbuf_len // Number of bytes of data to read or 0 141 | ) { 142 | return i2c_dma_write_read(i2c_dma, addr, NULL, 0, rbuf, rbuf_len); 143 | } 144 | 145 | // Writes a byte to a register. 146 | // 147 | // I2C Transaction: 148 | // S addr Wr [A] reg [A] byte [A] P 149 | // 150 | // Returns 151 | // PICO_OK 152 | // Function completed successfully 153 | // PICO_ERROR_INVALID_ARG 154 | // Invalid argument passed to function 155 | // PICO_ERROR_TIMEOUT 156 | // Timeout waiting to take a mutex 157 | // Timeout waiting for I2C transaction to complete 158 | // PICO_ERROR_IO 159 | // I2C transaction aborted by I2C peripheral 160 | // No stop condition for transaction detected by I2C peripheral 161 | // PICO_ERROR_GENERIC 162 | // Error attempting to give a mutex 163 | // Error attemptimg to claim a DMA channel 164 | static inline int i2c_dma_write_byte( 165 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 166 | uint8_t addr, // 7 bit I2C address 167 | uint8_t reg, // Number of the register to write to 168 | uint8_t byte // Byte to write 169 | ) { 170 | const uint8_t wbuf[2] = {reg, byte}; 171 | return i2c_dma_write_read(i2c_dma, addr, wbuf, 2, NULL, 0); 172 | } 173 | 174 | // Reads a byte from a register. 175 | // 176 | // I2C Transaction: 177 | // S addr Wr [A] reg [A] Sr addr Rd [A] [byte] NA P 178 | // 179 | // Returns 180 | // PICO_OK 181 | // Function completed successfully 182 | // PICO_ERROR_INVALID_ARG 183 | // Invalid argument passed to function 184 | // PICO_ERROR_TIMEOUT 185 | // Timeout waiting to take a mutex 186 | // Timeout waiting for I2C transaction to complete 187 | // PICO_ERROR_IO 188 | // I2C transaction aborted by I2C peripheral 189 | // No stop condition for transaction detected by I2C peripheral 190 | // PICO_ERROR_GENERIC 191 | // Error attempting to give a mutex 192 | // Error attemptimg to claim a DMA channel 193 | static inline int i2c_dma_read_byte( 194 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 195 | uint8_t addr, // 7 bit I2C address 196 | uint8_t reg, // Number of the register to read from 197 | uint8_t *byte // Pointer to the byte for the data read 198 | ) { 199 | return i2c_dma_write_read(i2c_dma, addr, ®, 1, byte, 1); 200 | } 201 | 202 | // Writes a 16-bit word to a register. The least significant byte is sent 203 | // over the wire first. 204 | // 205 | // I2C Transaction: 206 | // S addr Wr [A] reg [A] word lsb [A] word msb [A] P 207 | // 208 | // Returns 209 | // PICO_OK 210 | // Function completed successfully 211 | // PICO_ERROR_INVALID_ARG 212 | // Invalid argument passed to function 213 | // PICO_ERROR_TIMEOUT 214 | // Timeout waiting to take a mutex 215 | // Timeout waiting for I2C transaction to complete 216 | // PICO_ERROR_IO 217 | // I2C transaction aborted by I2C peripheral 218 | // No stop condition for transaction detected by I2C peripheral 219 | // PICO_ERROR_GENERIC 220 | // Error attempting to give a mutex 221 | // Error attemptimg to claim a DMA channel 222 | static inline int i2c_dma_write_word( 223 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 224 | uint8_t addr, // 7 bit I2C address 225 | uint8_t reg, // Number of the register to write to 226 | uint16_t word // 16-bit word to write 227 | ) { 228 | const uint8_t wbuf[3] = {reg, word & 0xff, word >> 8}; 229 | return i2c_dma_write_read(i2c_dma, addr, wbuf, 3, NULL, 0); 230 | } 231 | 232 | // Reads a 16-bit word from a register. The least significant byte is received 233 | // over the wire first. 234 | // 235 | // I2C Transaction: 236 | // S addr Wr [A] reg [A] Sr addr Rd [A] [word lsb] A [word msb] NA P 237 | // 238 | // Returns 239 | // PICO_OK 240 | // Function completed successfully 241 | // PICO_ERROR_INVALID_ARG 242 | // Invalid argument passed to function 243 | // PICO_ERROR_TIMEOUT 244 | // Timeout waiting to take a mutex 245 | // Timeout waiting for I2C transaction to complete 246 | // PICO_ERROR_IO 247 | // I2C transaction aborted by I2C peripheral 248 | // No stop condition for transaction detected by I2C peripheral 249 | // PICO_ERROR_GENERIC 250 | // Error attempting to give a mutex 251 | // Error attemptimg to claim a DMA channel 252 | static inline int i2c_dma_read_word( 253 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 254 | uint8_t addr, // 7 bit I2C address 255 | uint8_t reg, // Number of the register to read from 256 | uint16_t *word // Pointer to the 16-bit word for the data read 257 | ) { 258 | return i2c_dma_write_read(i2c_dma, addr, ®, 1, (uint8_t *) word, 2); 259 | } 260 | 261 | // Writes a 16-bit word to a register. The most significant byte is sent 262 | // over the wire first. 263 | // 264 | // I2C Transaction: 265 | // S addr Wr [A] reg [A] word msb [A] word lsb [A] P 266 | // 267 | // Returns 268 | // PICO_OK 269 | // Function completed successfully 270 | // PICO_ERROR_INVALID_ARG 271 | // Invalid argument passed to function 272 | // PICO_ERROR_TIMEOUT 273 | // Timeout waiting to take a mutex 274 | // Timeout waiting for I2C transaction to complete 275 | // PICO_ERROR_IO 276 | // I2C transaction aborted by I2C peripheral 277 | // No stop condition for transaction detected by I2C peripheral 278 | // PICO_ERROR_GENERIC 279 | // Error attempting to give a mutex 280 | // Error attemptimg to claim a DMA channel 281 | static inline int i2c_dma_write_word_swapped( 282 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 283 | uint8_t addr, // 7 bit I2C address 284 | uint8_t reg, // Number of the register to write to 285 | uint16_t word // 16-bit word to write 286 | ) { 287 | const uint8_t wbuf[3] = {reg, word >> 8, word & 0xff}; 288 | return i2c_dma_write_read(i2c_dma, addr, wbuf, 3, NULL, 0); 289 | } 290 | 291 | // Reads a 16-bit word from a register. The most significant byte is received 292 | // over the wire first. 293 | // 294 | // I2C Transaction: 295 | // S addr Wr [A] reg [A] Sr addr Rd [A] [word msb] A [word lsb] NA P 296 | // 297 | // Returns 298 | // PICO_OK 299 | // Function completed successfully 300 | // PICO_ERROR_INVALID_ARG 301 | // Invalid argument passed to function 302 | // PICO_ERROR_TIMEOUT 303 | // Timeout waiting to take a mutex 304 | // Timeout waiting for I2C transaction to complete 305 | // PICO_ERROR_IO 306 | // I2C transaction aborted by I2C peripheral 307 | // No stop condition for transaction detected by I2C peripheral 308 | // PICO_ERROR_GENERIC 309 | // Error attempting to give a mutex 310 | // Error attemptimg to claim a DMA channel 311 | static inline int i2c_dma_read_word_swapped( 312 | i2c_dma_t *i2c_dma, // i2c_dma_t pointer for I2C0 or I2C1 313 | uint8_t addr, // 7 bit I2C address 314 | uint8_t reg, // Number of the register to read from 315 | uint16_t *word // Pointer to the 16-bit word for the data read 316 | ) { 317 | int rc = i2c_dma_write_read(i2c_dma, addr, ®, 1, (uint8_t *) word, 2); 318 | *word = *word << 8 | *word >> 8; 319 | return rc; 320 | } 321 | 322 | #ifdef __cplusplus 323 | } 324 | #endif 325 | 326 | #endif 327 | 328 | --------------------------------------------------------------------------------