Add kernel drivers for SPI and UART and make locking APIs more consistent (#489)

- Add kernel support for SPI driver
- Add kernel support for UART driver
- Implemented ESP32 UART kernel driver
- Update existing UART-related code in Tactility to use new kernel driver
- Remove UART from tt::hal::Configuration
- Remove tt_hal_uart functionality but keep functions for now
- Update devicetrees for UART changes
- Kernel mutex and recursive mutex: improved locking API design
- Other kernel improvements
- Added device_exists_of_type() and device_find_by_name()
This commit is contained in:
Ken Van Hoeylandt
2026-02-07 21:28:11 +01:00
committed by GitHub
parent 7e24105d0c
commit 74127a5f6c
119 changed files with 1679 additions and 1792 deletions
@@ -32,12 +32,7 @@ inline static void mutex_lock(struct Mutex* mutex) {
xSemaphoreTake(mutex->handle, portMAX_DELAY);
}
inline static bool mutex_try_lock(struct Mutex* mutex) {
check(xPortInIsrContext() != pdTRUE);
return xSemaphoreTake(mutex->handle, 0) == pdTRUE;
}
inline static bool mutex_try_lock_timed(struct Mutex* mutex, TickType_t timeout) {
inline static bool mutex_try_lock(struct Mutex* mutex, TickType_t timeout) {
check(xPortInIsrContext() != pdTRUE);
return xSemaphoreTake(mutex->handle, timeout) == pdTRUE;
}
@@ -39,12 +39,7 @@ inline static bool recursive_mutex_is_locked(struct RecursiveMutex* mutex) {
}
}
inline static bool recursive_mutex_try_lock(struct RecursiveMutex* mutex) {
check(xPortInIsrContext() != pdTRUE);
return xSemaphoreTakeRecursive(mutex->handle, 0) == pdTRUE;
}
inline static bool recursive_mutex_try_lock_timed(struct RecursiveMutex* mutex, TickType_t timeout) {
inline static bool recursive_mutex_try_lock(struct RecursiveMutex* mutex, TickType_t timeout) {
check(xPortInIsrContext() != pdTRUE);
return xSemaphoreTakeRecursive(mutex->handle, timeout) == pdTRUE;
}
+19 -1
View File
@@ -10,6 +10,7 @@
#include <stdint.h>
#include <tactility/concurrent/mutex.h>
#include <tactility/freertos/freertos.h>
#ifdef __cplusplus
extern "C" {
@@ -212,9 +213,10 @@ void device_lock(struct Device* device);
* Try to lock the device for exclusive access.
*
* @param[in,out] device non-null device pointer
* @param[in] timeout how long to wait for the lock
* @return true if the device was locked successfully
*/
bool device_try_lock(struct Device* device);
bool device_try_lock(struct Device* device, TickType_t timeout);
/**
* Unlock the device.
@@ -257,6 +259,22 @@ void device_for_each_child(struct Device* device, void* callback_context, bool(*
*/
void device_for_each_of_type(const struct DeviceType* type, void* callback_context, bool(*on_device)(struct Device* device, void* context));
/**
* Check if a device of the specified type exists.
*
* @param[in] type the type to check
* @return true if a device of the specified type exists
*/
bool device_exists_of_type(const struct DeviceType* type);
/**
* Find a device by its name.
*
* @param[in] name non-null device name to look up
* @return the device pointer if found, or NULL if not found
*/
struct Device* device_find_by_name(const char* name);
#ifdef __cplusplus
}
#endif
@@ -9,6 +9,8 @@ extern "C" {
#include "gpio.h"
#include <tactility/error.h>
struct Device;
struct GpioControllerApi {
/**
* @brief Sets the logical level of a GPIO pin.
@@ -13,6 +13,8 @@ extern "C" {
#include <tactility/freertos/freertos.h>
#include <tactility/error.h>
struct Device;
/**
* @brief API for I2C controller drivers.
*/
@@ -14,6 +14,8 @@ extern "C" {
#include <tactility/freertos/freertos.h>
#include <tactility/error.h>
struct Device;
/**
* @brief I2S communication format
*/
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include <tactility/freertos/freertos.h>
#include <tactility/error.h>
struct Device;
/**
* @brief API for SPI controller drivers.
*/
struct SpiControllerApi {
/**
* @brief Locks the SPI controller.
* @param[in] device the SPI controller device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*lock)(struct Device* device);
/**
* @brief Tries to lock the SPI controller.
* @param[in] device the SPI controller device
* @param[in] timeout the maximum time to wait for the lock
* @retval ERROR_NONE when the operation was successful
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*try_lock)(struct Device* device, TickType_t timeout);
/**
* @brief Unlocks the SPI controller.
* @param[in] device the SPI controller device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*unlock)(struct Device* device);
};
/**
* @brief Locks the SPI controller using the specified controller.
* @param[in] device the SPI controller device
* @retval ERROR_NONE when the operation was successful
*/
error_t spi_controller_lock(struct Device* device);
/**
* @brief Tries to lock the SPI controller using the specified controller.
* @param[in] device the SPI controller device
* @param[in] timeout the maximum ticks to wait for the lock
* @retval ERROR_NONE when the operation was successful
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t spi_controller_try_lock(struct Device* device, TickType_t timeout);
/**
* @brief Unlocks the SPI controller using the specified controller.
* @param[in] device the SPI controller device
* @retval ERROR_NONE when the operation was successful
*/
error_t spi_controller_unlock(struct Device* device);
extern const struct DeviceType SPI_CONTROLLER_TYPE;
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,227 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include <tactility/freertos/freertos.h>
#include <tactility/error.h>
struct Device;
/**
* @brief UART parity modes
*/
enum UartParity {
UART_CONTROLLER_PARITY_DISABLE = 0x0,
UART_CONTROLLER_PARITY_EVEN = 0x1,
UART_CONTROLLER_PARITY_ODD = 0x2,
};
/**
* @brief UART data bits
*/
enum UartDataBits {
UART_CONTROLLER_DATA_5_BITS = 0x0,
UART_CONTROLLER_DATA_6_BITS = 0x1,
UART_CONTROLLER_DATA_7_BITS = 0x2,
UART_CONTROLLER_DATA_8_BITS = 0x3,
};
/**
* @brief UART stop bits
*/
enum UartStopBits {
UART_CONTROLLER_STOP_BITS_1 = 0x1,
UART_CONTROLLER_STOP_BITS_1_5 = 0x2,
UART_CONTROLLER_STOP_BITS_2 = 0x3,
};
/**
* @brief UART Config
*/
struct UartConfig {
uint32_t baud_rate;
enum UartDataBits data_bits;
enum UartParity parity;
enum UartStopBits stop_bits;
};
/**
* @brief API for UART controller drivers.
*/
struct UartControllerApi {
/**
* @brief Reads a single byte from UART.
* @param[in] device the UART controller device
* @param[out] out the buffer to store the read byte
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE when the read operation was successful
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*read_byte)(struct Device* device, uint8_t* out, TickType_t timeout);
/**
* @brief Writes a single byte to UART.
* @param[in] device the UART controller device
* @param[in] out the byte to write
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE when the write operation was successful
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*write_byte)(struct Device* device, uint8_t out, TickType_t timeout);
/**
* @brief Writes multiple bytes to UART.
* @param[in] device the UART controller device
* @param[in] buffer the buffer containing the data to write
* @param[in] buffer_size the number of bytes to write
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE when the write operation was successful
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*write_bytes)(struct Device* device, const uint8_t* buffer, size_t buffer_size, TickType_t timeout);
/**
* @brief Reads multiple bytes from UART.
* @param[in] device the UART controller device
* @param[out] buffer the buffer to store the read data
* @param[in] buffer_size the number of bytes to read
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE when the read operation was successful
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*read_bytes)(struct Device* device, uint8_t* buffer, size_t buffer_size, TickType_t timeout);
/**
* @brief Returns the number of bytes available for reading.
* @param[in] device the UART controller device
* @param[out] available the number of bytes available
* @return ERROR_NONE on success
*/
error_t (*get_available)(struct Device* device, size_t* available);
/**
* @brief Sets the UART configuration.
* @param[in] device the UART controller device
* @param[in] config the new configuration
* @retval ERROR_NONE when the operation was successful
*/
error_t (*set_config)(struct Device* device, const struct UartConfig* config);
/**
* @brief Gets the current UART configuration.
* @param[in] device the UART controller device
* @param[out] config the buffer to store the current configuration
* @retval ERROR_NONE when the operation was successful
*/
error_t (*get_config)(struct Device* device, struct UartConfig* config);
/**
* @brief Opens the UART controller.
* @param[in] device the UART controller device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*open)(struct Device* device);
/**
* @brief Closes the UART controller.
* @param[in] device the UART controller device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*close)(struct Device* device);
/**
* @brief Checks if the UART controller is open.
* @param[in] device the UART controller device
* @return true if open, false otherwise
*/
bool (*is_open)(struct Device* device);
/**
* @brief Flushes the UART input buffer.
* @param[in] device the UART controller device
* @retval ERROR_NONE when the operation was successful
*/
error_t (*flush_input)(struct Device* device);
};
/**
* @brief Reads a single byte from UART using the specified controller.
*/
error_t uart_controller_read_byte(struct Device* device, uint8_t* out, TickType_t timeout);
/**
* @brief Writes a single byte to UART using the specified controller.
*/
error_t uart_controller_write_byte(struct Device* device, uint8_t out, TickType_t timeout);
/**
* @brief Writes multiple bytes to UART using the specified controller.
*/
error_t uart_controller_write_bytes(struct Device* device, const uint8_t* buffer, size_t buffer_size, TickType_t timeout);
/**
* @brief Reads multiple bytes from UART using the specified controller.
*/
error_t uart_controller_read_bytes(struct Device* device, uint8_t* buffer, size_t buffer_size, TickType_t timeout);
/**
* @brief Reads from UART until a specific byte is encountered.
* @param[in] device the UART controller device
* @param[out] buffer the buffer to store the read data
* @param[in] buffer_size the size of the buffer
* @param[in] until_byte the byte to look for
* @param[in] timeout the maximum time to wait for the operation to complete
* @param[in] add_null_terminator whether to add a null terminator after the until_byte
* @param[out] bytes_read the number of bytes read (excluding null terminator if added)
* @retval ERROR_NONE when the operation was successful
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t uart_controller_read_until(struct Device* device, uint8_t* buffer, size_t buffer_size, uint8_t until_byte, bool add_null_terminator, size_t* bytes_read, TickType_t timeout);
/**
* @brief Get the number of bytes available for reading using the specified controller.
*/
error_t uart_controller_get_available(struct Device* device, size_t* available);
/**
* @brief Sets the UART configuration using the specified controller.
*/
error_t uart_controller_set_config(struct Device* device, const struct UartConfig* config);
/**
* @brief Gets the current UART configuration using the specified controller.
*/
error_t uart_controller_get_config(struct Device* device, struct UartConfig* config);
/**
* @brief Opens the UART controller using the specified controller.
*/
error_t uart_controller_open(struct Device* device);
/**
* @brief Closes the UART controller using the specified controller.
*/
error_t uart_controller_close(struct Device* device);
/**
* @brief Checks if the UART controller is open using the specified controller.
*/
bool uart_controller_is_open(struct Device* device);
/**
* @brief Flushes the UART input buffer using the specified controller.
*/
error_t uart_controller_flush_input(struct Device* device);
extern const struct DeviceType UART_CONTROLLER_TYPE;
#ifdef __cplusplus
}
#endif