Add full automotive RTOS project

Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers,
middleware (CAN stack, diagnostics, safety), applications, board
support, build/test tooling, and documentation.
This commit is contained in:
root
2026-08-23 03:35:29 -04:00
parent f113bf0a05
commit ca13734bf0
151 changed files with 23945 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
/**
* @file adc_driver.h
* @brief ADC driver interface
*/
#ifndef ADC_DRIVER_H
#define ADC_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
/* ADC Configuration Constants */
#define ADC_MAX_INSTANCES 3
#define ADC_MAX_CHANNELS 16
#define ADC_MAX_SEQUENCES 8
/* ADC Resolution */
typedef enum {
ADC_RESOLUTION_6BIT = 6,
ADC_RESOLUTION_8BIT = 8,
ADC_RESOLUTION_10BIT = 10,
ADC_RESOLUTION_12BIT = 12,
ADC_RESOLUTION_14BIT = 14,
ADC_RESOLUTION_16BIT = 16
} AdcResolution_t;
/* ADC Conversion Modes */
typedef enum {
ADC_MODE_SINGLE = 0,
ADC_MODE_CONTINUOUS = 1,
ADC_MODE_SCAN = 2,
ADC_MODE_DISCONTINUOUS = 3
} AdcConversionMode_t;
/* ADC Trigger Sources */
typedef enum {
ADC_TRIGGER_SOFTWARE = 0,
ADC_TRIGGER_TIMER = 1,
ADC_TRIGGER_EXTERNAL = 2
} AdcTriggerSource_t;
/* ADC Reference Voltage */
typedef enum {
ADC_REFERENCE_INTERNAL = 0,
ADC_REFERENCE_EXTERNAL = 1,
ADC_REFERENCE_VDD = 2
} AdcReference_t;
/* ADC Sampling Time */
typedef enum {
ADC_SAMPLING_1_5_CYCLES = 0,
ADC_SAMPLING_7_5_CYCLES = 1,
ADC_SAMPLING_13_5_CYCLES = 2,
ADC_SAMPLING_28_5_CYCLES = 3,
ADC_SAMPLING_41_5_CYCLES = 4,
ADC_SAMPLING_55_5_CYCLES = 5,
ADC_SAMPLING_71_5_CYCLES = 6,
ADC_SAMPLING_239_5_CYCLES = 7
} AdcSamplingTime_t;
/* ADC Callbacks */
typedef void (*AdcConversionCompleteCallback_t)(uint16_t* values, uint8_t count);
/* ADC Channel Configuration */
typedef struct {
uint8_t channel;
AdcSamplingTime_t sampling_time;
bool enable_watchdog;
uint16_t watchdog_high_threshold;
uint16_t watchdog_low_threshold;
} AdcChannelConfig_t;
/* ADC Configuration */
typedef struct {
AdcResolution_t resolution;
AdcConversionMode_t mode;
AdcTriggerSource_t trigger_source;
AdcReference_t reference;
bool enable_dma;
uint32_t conversion_frequency;
AdcChannelConfig_t channels[ADC_MAX_CHANNELS];
uint8_t channel_count;
AdcConversionCompleteCallback_t conversion_complete_callback;
} AdcConfig_t;
/* ADC Statistics */
typedef struct {
uint32_t conversions_completed;
uint32_t conversions_failed;
uint32_t watchdog_events;
uint32_t overrun_errors;
uint32_t dma_transfers;
uint32_t average_conversion_time_us;
} AdcStatistics_t;
/* ADC Driver Interface */
KernelStatus_t adc_init(uint8_t instance, AdcConfig_t* config);
KernelStatus_t adc_deinit(uint8_t instance);
KernelStatus_t adc_start_conversion(uint8_t instance);
KernelStatus_t adc_stop_conversion(uint8_t instance);
KernelStatus_t adc_read_channel(uint8_t instance, uint8_t channel, uint16_t* value,
uint32_t timeout_ms);
KernelStatus_t adc_read_channels(uint8_t instance, uint16_t* values, uint8_t count,
uint32_t timeout_ms);
KernelStatus_t adc_start_dma(uint8_t instance, uint16_t* buffer, uint16_t length);
KernelStatus_t adc_stop_dma(uint8_t instance);
KernelStatus_t adc_calibrate(uint8_t instance);
KernelStatus_t adc_get_statistics(uint8_t instance, AdcStatistics_t* stats);
float adc_convert_to_voltage(uint16_t adc_value, AdcResolution_t resolution,
float reference_voltage);
void adc_process_interrupt(uint8_t instance);
#endif /* ADC_DRIVER_H */
+120
View File
@@ -0,0 +1,120 @@
/**
* @file can_driver.h
* @brief CAN (Controller Area Network) driver interface
* @note Supports classical CAN and CAN FD
*/
#ifndef CAN_DRIVER_H
#define CAN_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
/* CAN Configuration Constants */
#define CAN_MAX_MESSAGE_LENGTH 8 /* Classical CAN */
#define CAN_FD_MAX_MESSAGE_LENGTH 64 /* CAN FD */
#define CAN_MAX_FILTERS 32
#define CAN_MAX_TX_MAILBOXES 3
#define CAN_MAX_RX_FIFO_DEPTH 16
/* CAN Baudrates */
typedef enum {
CAN_BAUD_125K = 125000,
CAN_BAUD_250K = 250000,
CAN_BAUD_500K = 500000,
CAN_BAUD_1M = 1000000,
CAN_FD_BAUD_2M = 2000000,
CAN_FD_BAUD_5M = 5000000
} CanBaudrate_t;
/* CAN Message Types */
typedef enum {
CAN_FRAME_CLASSIC = 0,
CAN_FRAME_FD = 1,
CAN_FRAME_FD_BRS = 2 /* FD with Bit Rate Switch */
} CanFrameType_t;
/* CAN Frame Format */
typedef enum {
CAN_FORMAT_STANDARD = 0, /* 11-bit identifier */
CAN_FORMAT_EXTENDED = 1 /* 29-bit identifier */
} CanFrameFormat_t;
/* CAN Message ID */
typedef struct {
uint32_t id : 29;
CanFrameFormat_t format : 1;
bool is_remote : 1;
bool is_extended : 1;
} CanMessageId_t;
/* CAN Message Structure */
typedef struct {
CanMessageId_t id;
CanFrameType_t type;
uint8_t data[CAN_FD_MAX_MESSAGE_LENGTH];
uint8_t length;
uint32_t timestamp;
bool is_rx;
} CanMessage_t;
/* CAN Filter Configuration */
typedef struct {
uint32_t filter_id;
uint32_t filter_mask;
CanFrameFormat_t format;
bool enable;
} CanFilterConfig_t;
/* CAN Statistics */
typedef struct {
uint32_t tx_messages;
uint32_t rx_messages;
uint32_t tx_errors;
uint32_t rx_errors;
uint32_t bus_off_count;
uint32_t error_warning_count;
uint32_t error_passive_count;
uint32_t tx_overflow;
uint32_t rx_overflow;
} CanStatistics_t;
/* CAN Callbacks */
typedef void (*CanRxCallback_t)(const CanMessage_t* message);
typedef void (*CanTxCallback_t)(uint32_t mailbox, bool success);
typedef void (*CanErrorCallback_t)(uint32_t error_code);
/* CAN Configuration Structure */
typedef struct {
CanBaudrate_t nominal_baudrate;
CanBaudrate_t data_baudrate; /* For CAN FD */
CanFrameType_t frame_type;
bool enable_fd;
bool enable_automatic_retransmission;
CanFilterConfig_t filters[CAN_MAX_FILTERS];
uint8_t filter_count;
CanRxCallback_t rx_callback;
CanTxCallback_t tx_callback;
CanErrorCallback_t error_callback;
} CanConfig_t;
/* CAN Driver Interface */
KernelStatus_t can_init(CanConfig_t* config);
KernelStatus_t can_deinit(void);
KernelStatus_t can_send_message(const CanMessage_t* message, uint32_t timeout_ms);
KernelStatus_t can_receive_message(CanMessage_t* message, uint32_t timeout_ms);
KernelStatus_t can_configure_filter(const CanFilterConfig_t* filter);
KernelStatus_t can_set_baudrate(CanBaudrate_t baudrate);
KernelStatus_t can_get_statistics(CanStatistics_t* stats);
KernelStatus_t can_clear_statistics(void);
bool can_is_bus_off(void);
KernelStatus_t can_recover_bus_off(void);
void can_process_interrupt(void);
/* CAN FD Specific Functions */
KernelStatus_t can_fd_set_data_baudrate(CanBaudrate_t baudrate);
KernelStatus_t can_fd_set_transmit_delay(uint16_t delay_us);
bool can_fd_is_enabled(void);
#endif /* CAN_DRIVER_H */
+113
View File
@@ -0,0 +1,113 @@
/**
* @file gpio_driver.h
* @brief GPIO driver interface
*/
#ifndef GPIO_DRIVER_H
#define GPIO_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
/* GPIO Configuration Constants */
#define GPIO_MAX_PORTS 8
#define GPIO_MAX_PINS_PER_PORT 16
#define GPIO_MAX_INTERRUPTS 32
/* GPIO Modes */
typedef enum {
GPIO_MODE_INPUT = 0,
GPIO_MODE_OUTPUT = 1,
GPIO_MODE_ALTERNATE = 2,
GPIO_MODE_ANALOG = 3
} GpioMode_t;
/* GPIO Output Types */
typedef enum {
GPIO_OUTPUT_PUSH_PULL = 0,
GPIO_OUTPUT_OPEN_DRAIN = 1
} GpioOutputType_t;
/* GPIO Pull Configuration */
typedef enum {
GPIO_PULL_NONE = 0,
GPIO_PULL_UP = 1,
GPIO_PULL_DOWN = 2
} GpioPull_t;
/* GPIO Speed */
typedef enum {
GPIO_SPEED_LOW = 0,
GPIO_SPEED_MEDIUM = 1,
GPIO_SPEED_HIGH = 2,
GPIO_SPEED_VERY_HIGH = 3
} GpioSpeed_t;
/* GPIO Alternate Functions */
typedef enum {
GPIO_AF0 = 0,
GPIO_AF1 = 1,
GPIO_AF2 = 2,
GPIO_AF3 = 3,
GPIO_AF4 = 4,
GPIO_AF5 = 5,
GPIO_AF6 = 6,
GPIO_AF7 = 7,
GPIO_AF8 = 8,
GPIO_AF9 = 9,
GPIO_AF10 = 10,
GPIO_AF11 = 11,
GPIO_AF12 = 12,
GPIO_AF13 = 13,
GPIO_AF14 = 14,
GPIO_AF15 = 15
} GpioAlternateFunction_t;
/* GPIO Interrupt Triggers */
typedef enum {
GPIO_INTERRUPT_NONE = 0,
GPIO_INTERRUPT_RISING = 1,
GPIO_INTERRUPT_FALLING = 2,
GPIO_INTERRUPT_BOTH = 3
} GpioInterruptTrigger_t;
/* GPIO Pin Configuration */
typedef struct {
uint8_t port;
uint8_t pin;
GpioMode_t mode;
GpioOutputType_t output_type;
GpioPull_t pull;
GpioSpeed_t speed;
GpioAlternateFunction_t alternate_function;
} GpioPinConfig_t;
/* GPIO Interrupt Configuration */
typedef struct {
uint8_t port;
uint8_t pin;
GpioInterruptTrigger_t trigger;
void (*callback)(uint8_t port, uint8_t pin);
} GpioInterruptConfig_t;
/* GPIO Driver Interface */
KernelStatus_t gpio_init(const GpioPinConfig_t* config);
KernelStatus_t gpio_deinit(uint8_t port, uint8_t pin);
KernelStatus_t gpio_set_mode(uint8_t port, uint8_t pin, GpioMode_t mode);
KernelStatus_t gpio_set_output_type(uint8_t port, uint8_t pin, GpioOutputType_t type);
KernelStatus_t gpio_set_pull(uint8_t port, uint8_t pin, GpioPull_t pull);
KernelStatus_t gpio_set_speed(uint8_t port, uint8_t pin, GpioSpeed_t speed);
KernelStatus_t gpio_set_alternate_function(uint8_t port, uint8_t pin,
GpioAlternateFunction_t af);
KernelStatus_t gpio_write(uint8_t port, uint8_t pin, bool value);
KernelStatus_t gpio_write_port(uint8_t port, uint16_t value);
bool gpio_read(uint8_t port, uint8_t pin);
uint16_t gpio_read_port(uint8_t port);
KernelStatus_t gpio_toggle(uint8_t port, uint8_t pin);
KernelStatus_t gpio_configure_interrupt(const GpioInterruptConfig_t* config);
KernelStatus_t gpio_enable_interrupt(uint8_t port, uint8_t pin);
KernelStatus_t gpio_disable_interrupt(uint8_t port, uint8_t pin);
void gpio_process_interrupt(uint8_t port);
#endif /* GPIO_DRIVER_H */
+101
View File
@@ -0,0 +1,101 @@
/**
* @file i2c_driver.h
* @brief I2C driver interface
*/
#ifndef I2C_DRIVER_H
#define I2C_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
/* I2C Configuration Constants */
#define I2C_MAX_INSTANCES 4
#define I2C_MAX_BUFFER_SIZE 1024
#define I2C_MAX_TRANSFER_SIZE 255
/* I2C Speeds */
typedef enum {
I2C_SPEED_STANDARD = 100000, /* 100 kHz */
I2C_SPEED_FAST = 400000, /* 400 kHz */
I2C_SPEED_FAST_PLUS = 1000000, /* 1 MHz */
I2C_SPEED_HIGH = 3400000 /* 3.4 MHz */
} I2cSpeed_t;
/* I2C Addressing Mode */
typedef enum {
I2C_ADDRESSING_7BIT = 0,
I2C_ADDRESSING_10BIT = 1
} I2cAddressingMode_t;
/* I2C Transfer Direction */
typedef enum {
I2C_DIRECTION_WRITE = 0,
I2C_DIRECTION_READ = 1
} I2cDirection_t;
/* I2C Transfer Status */
typedef enum {
I2C_TRANSFER_COMPLETE = 0,
I2C_TRANSFER_ERROR = 1,
I2C_TRANSFER_NACK = 2,
I2C_TRANSFER_TIMEOUT = 3,
I2C_TRANSFER_ARBITRATION_LOST = 4,
I2C_TRANSFER_BUS_ERROR = 5
} I2cTransferStatus_t;
/* I2C Callbacks */
typedef void (*I2cTransferCompleteCallback_t)(I2cTransferStatus_t status, void* user_data);
/* I2C Configuration */
typedef struct {
I2cSpeed_t speed;
I2cAddressingMode_t addressing_mode;
uint16_t own_address;
bool enable_general_call;
bool enable_clock_stretching;
bool use_dma;
I2cTransferCompleteCallback_t transfer_complete_callback;
} I2cConfig_t;
/* I2C Message */
typedef struct {
uint16_t slave_address;
I2cDirection_t direction;
uint8_t* data;
uint16_t length;
bool generate_stop;
bool generate_restart;
} I2cMessage_t;
/* I2C Statistics */
typedef struct {
uint32_t transfers_completed;
uint32_t transfers_failed;
uint32_t nack_errors;
uint32_t arbitration_lost;
uint32_t bus_errors;
uint32_t timeout_errors;
uint32_t bytes_transferred;
} I2cStatistics_t;
/* I2C Driver Interface */
KernelStatus_t i2c_init(uint8_t instance, I2cConfig_t* config);
KernelStatus_t i2c_deinit(uint8_t instance);
KernelStatus_t i2c_transfer(uint8_t instance, const I2cMessage_t* message,
uint32_t timeout_ms);
KernelStatus_t i2c_transfer_async(uint8_t instance, const I2cMessage_t* message);
KernelStatus_t i2c_write(uint8_t instance, uint16_t slave_address,
const uint8_t* data, uint16_t length, uint32_t timeout_ms);
KernelStatus_t i2c_read(uint8_t instance, uint16_t slave_address,
uint8_t* data, uint16_t length, uint32_t timeout_ms);
KernelStatus_t i2c_write_read(uint8_t instance, uint16_t slave_address,
const uint8_t* tx_data, uint16_t tx_length,
uint8_t* rx_data, uint16_t rx_length,
uint32_t timeout_ms);
KernelStatus_t i2c_get_statistics(uint8_t instance, I2cStatistics_t* stats);
bool i2c_is_device_ready(uint8_t instance, uint16_t slave_address);
void i2c_process_interrupt(uint8_t instance);
#endif /* I2C_DRIVER_H */
+105
View File
@@ -0,0 +1,105 @@
/**
* @file pwm_driver.h
* @brief PWM driver interface
*/
#ifndef PWM_DRIVER_H
#define PWM_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
/* PWM Configuration Constants */
#define PWM_MAX_INSTANCES 8
#define PWM_MAX_CHANNELS 4
#define PWM_MAX_DUTY_CYCLE 10000 /* 100.00% in 0.01% steps */
/* PWM Alignment Modes */
typedef enum {
PWM_ALIGNMENT_EDGE = 0,
PWM_ALIGNMENT_CENTER = 1
} PwmAlignment_t;
/* PWM Polarity */
typedef enum {
PWM_POLARITY_ACTIVE_HIGH = 0,
PWM_POLARITY_ACTIVE_LOW = 1
} PwmPolarity_t;
/* PWM Modes */
typedef enum {
PWM_MODE_NORMAL = 0,
PWM_MODE_COMPLEMENTARY = 1,
PWM_MODE_COMBINED = 2
} PwmMode_t;
/* PWM Dead Time */
typedef struct {
uint16_t rising_edge_delay_ns;
uint16_t falling_edge_delay_ns;
} PwmDeadTime_t;
/* PWM Fault Actions */
typedef enum {
PWM_FAULT_DISABLE = 0,
PWM_FAULT_ENABLE = 1,
PWM_FAULT_HIGH_Z = 2
} PwmFaultAction_t;
/* PWM Callbacks */
typedef void (*PwmPeriodElapsedCallback_t)(uint8_t instance);
typedef void (*PwmFaultCallback_t)(uint8_t instance, uint32_t fault_flags);
/* PWM Channel Configuration */
typedef struct {
uint8_t channel;
uint32_t duty_cycle; /* 0 to PWM_MAX_DUTY_CYCLE */
PwmPolarity_t polarity;
PwmMode_t mode;
PwmDeadTime_t dead_time;
} PwmChannelConfig_t;
/* PWM Configuration */
typedef struct {
uint32_t frequency_hz;
PwmAlignment_t alignment;
uint32_t period_ticks;
uint8_t prescaler;
PwmChannelConfig_t channels[PWM_MAX_CHANNELS];
uint8_t channel_count;
bool enable_fault_protection;
PwmFaultAction_t fault_action;
PwmPeriodElapsedCallback_t period_elapsed_callback;
PwmFaultCallback_t fault_callback;
} PwmConfig_t;
/* PWM Statistics */
typedef struct {
uint32_t period_elapsed_count;
uint32_t fault_events;
uint32_t duty_cycle_updates;
uint32_t overcurrent_events;
uint32_t overvoltage_events;
} PwmStatistics_t;
/* PWM Driver Interface */
KernelStatus_t pwm_init(uint8_t instance, PwmConfig_t* config);
KernelStatus_t pwm_deinit(uint8_t instance);
KernelStatus_t pwm_start(uint8_t instance);
KernelStatus_t pwm_stop(uint8_t instance);
KernelStatus_t pwm_set_duty_cycle(uint8_t instance, uint8_t channel, uint32_t duty_cycle);
KernelStatus_t pwm_set_frequency(uint8_t instance, uint32_t frequency_hz);
KernelStatus_t pwm_set_period(uint8_t instance, uint32_t period_ticks);
KernelStatus_t pwm_set_dead_time(uint8_t instance, uint8_t channel,
const PwmDeadTime_t* dead_time);
KernelStatus_t pwm_enable_channel(uint8_t instance, uint8_t channel);
KernelStatus_t pwm_disable_channel(uint8_t instance, uint8_t channel);
KernelStatus_t pwm_configure_fault(uint8_t instance, PwmFaultAction_t action);
KernelStatus_t pwm_clear_fault(uint8_t instance);
KernelStatus_t pwm_get_statistics(uint8_t instance, PwmStatistics_t* stats);
uint32_t pwm_get_duty_cycle(uint8_t instance, uint8_t channel);
uint32_t pwm_get_frequency(uint8_t instance);
void pwm_process_interrupt(uint8_t instance);
#endif /* PWM_DRIVER_H */
+109
View File
@@ -0,0 +1,109 @@
/**
* @file spi_driver.h
* @brief SPI driver interface
*/
#ifndef SPI_DRIVER_H
#define SPI_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
/* SPI Configuration Constants */
#define SPI_MAX_INSTANCES 4
#define SPI_MAX_BUFFER_SIZE 4096
#define SPI_MAX_TRANSFER_SIZE 65535
/* SPI Modes */
typedef enum {
SPI_MODE_0 = 0, /* CPOL=0, CPHA=0 */
SPI_MODE_1 = 1, /* CPOL=0, CPHA=1 */
SPI_MODE_2 = 2, /* CPOL=1, CPHA=0 */
SPI_MODE_3 = 3 /* CPOL=1, CPHA=1 */
} SpiMode_t;
/* SPI Clock Speeds */
typedef enum {
SPI_CLOCK_1MHZ = 1000000,
SPI_CLOCK_2MHZ = 2000000,
SPI_CLOCK_4MHZ = 4000000,
SPI_CLOCK_8MHZ = 8000000,
SPI_CLOCK_16MHZ = 16000000,
SPI_CLOCK_32MHZ = 32000000
} SpiClockSpeed_t;
/* SPI Data Order */
typedef enum {
SPI_DATA_ORDER_MSB_FIRST = 0,
SPI_DATA_ORDER_LSB_FIRST = 1
} SpiDataOrder_t;
/* SPI Chip Select */
typedef enum {
SPI_CS_ACTIVE_LOW = 0,
SPI_CS_ACTIVE_HIGH = 1
} SpiChipSelectPolarity_t;
/* SPI Transfer Status */
typedef enum {
SPI_TRANSFER_COMPLETE = 0,
SPI_TRANSFER_ERROR = 1,
SPI_TRANSFER_TIMEOUT = 2,
SPI_TRANSFER_DMA_COMPLETE = 3
} SpiTransferStatus_t;
/* SPI Callbacks */
typedef void (*SpiTransferCompleteCallback_t)(SpiTransferStatus_t status, void* user_data);
/* SPI Configuration */
typedef struct {
SpiMode_t mode;
SpiClockSpeed_t clock_speed;
SpiDataOrder_t data_order;
uint8_t data_size; /* 8 or 16 bits */
bool use_dma;
bool enable_hardware_cs;
SpiChipSelectPolarity_t cs_polarity;
uint8_t cs_port;
uint8_t cs_pin;
SpiTransferCompleteCallback_t transfer_complete_callback;
} SpiConfig_t;
/* SPI Statistics */
typedef struct {
uint32_t transfers_completed;
uint32_t transfers_failed;
uint32_t bytes_transferred;
uint32_t dma_transfers;
uint32_t overrun_errors;
uint32_t underrun_errors;
uint32_t timeout_errors;
} SpiStatistics_t;
/* SPI Transaction */
typedef struct {
const uint8_t* tx_data;
uint8_t* rx_data;
uint16_t length;
bool keep_cs_active;
void* user_data;
} SpiTransaction_t;
/* SPI Driver Interface */
KernelStatus_t spi_init(uint8_t instance, SpiConfig_t* config);
KernelStatus_t spi_deinit(uint8_t instance);
KernelStatus_t spi_transfer(uint8_t instance, const SpiTransaction_t* transaction,
uint32_t timeout_ms);
KernelStatus_t spi_transfer_async(uint8_t instance, const SpiTransaction_t* transaction);
KernelStatus_t spi_read(uint8_t instance, uint8_t* data, uint16_t length,
uint32_t timeout_ms);
KernelStatus_t spi_write(uint8_t instance, const uint8_t* data, uint16_t length,
uint32_t timeout_ms);
KernelStatus_t spi_read_write(uint8_t instance, const uint8_t* tx_data,
uint8_t* rx_data, uint16_t length, uint32_t timeout_ms);
KernelStatus_t spi_get_statistics(uint8_t instance, SpiStatistics_t* stats);
void spi_set_chip_select(uint8_t instance, bool active);
void spi_process_interrupt(uint8_t instance);
#endif /* SPI_DRIVER_H */
+107
View File
@@ -0,0 +1,107 @@
/**
* @file uart_driver.h
* @brief UART driver interface
*/
#ifndef UART_DRIVER_H
#define UART_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
/* UART Configuration Constants */
#define UART_MAX_INSTANCES 6
#define UART_MAX_BUFFER_SIZE 2048
#define UART_DEFAULT_BAUDRATE 115200
/* UART Baudrates */
typedef enum {
UART_BAUD_9600 = 9600,
UART_BAUD_19200 = 19200,
UART_BAUD_38400 = 38400,
UART_BAUD_57600 = 57600,
UART_BAUD_115200 = 115200,
UART_BAUD_230400 = 230400,
UART_BAUD_460800 = 460800,
UART_BAUD_921600 = 921600
} UartBaudrate_t;
/* UART Data Bits */
typedef enum {
UART_DATA_BITS_5 = 5,
UART_DATA_BITS_6 = 6,
UART_DATA_BITS_7 = 7,
UART_DATA_BITS_8 = 8,
UART_DATA_BITS_9 = 9
} UartDataBits_t;
/* UART Stop Bits */
typedef enum {
UART_STOP_BITS_1 = 0,
UART_STOP_BITS_1_5 = 1,
UART_STOP_BITS_2 = 2
} UartStopBits_t;
/* UART Parity */
typedef enum {
UART_PARITY_NONE = 0,
UART_PARITY_EVEN = 1,
UART_PARITY_ODD = 2
} UartParity_t;
/* UART Flow Control */
typedef enum {
UART_FLOW_CONTROL_NONE = 0,
UART_FLOW_CONTROL_RTS_CTS = 1,
UART_FLOW_CONTROL_XON_XOFF = 2
} UartFlowControl_t;
/* UART Callbacks */
typedef void (*UartRxCallback_t)(uint8_t* data, uint16_t length);
typedef void (*UartTxCallback_t)(void);
typedef void (*UartErrorCallback_t)(uint32_t error);
/* UART Configuration */
typedef struct {
UartBaudrate_t baudrate;
UartDataBits_t data_bits;
UartStopBits_t stop_bits;
UartParity_t parity;
UartFlowControl_t flow_control;
bool enable_rx;
bool enable_tx;
bool use_dma;
UartRxCallback_t rx_callback;
UartTxCallback_t tx_callback;
UartErrorCallback_t error_callback;
} UartConfig_t;
/* UART Statistics */
typedef struct {
uint32_t tx_bytes;
uint32_t rx_bytes;
uint32_t tx_errors;
uint32_t rx_errors;
uint32_t parity_errors;
uint32_t framing_errors;
uint32_t overrun_errors;
uint32_t dma_transfers;
} UartStatistics_t;
/* UART Driver Interface */
KernelStatus_t uart_init(uint8_t instance, UartConfig_t* config);
KernelStatus_t uart_deinit(uint8_t instance);
KernelStatus_t uart_send(uint8_t instance, const uint8_t* data, uint16_t length,
uint32_t timeout_ms);
KernelStatus_t uart_receive(uint8_t instance, uint8_t* data, uint16_t length,
uint32_t timeout_ms);
KernelStatus_t uart_send_async(uint8_t instance, const uint8_t* data, uint16_t length);
KernelStatus_t uart_receive_async(uint8_t instance, uint8_t* data, uint16_t length);
KernelStatus_t uart_flush(uint8_t instance);
KernelStatus_t uart_get_statistics(uint8_t instance, UartStatistics_t* stats);
uint16_t uart_get_rx_count(uint8_t instance);
uint16_t uart_get_tx_count(uint8_t instance);
void uart_process_interrupt(uint8_t instance);
#endif /* UART_DRIVER_H */
@@ -0,0 +1,72 @@
/**
* @file tc3xx_config.h
* @brief Infineon TriCore TC3xx specific configuration
*/
#ifndef TC3XX_CONFIG_H
#define TC3XX_CONFIG_H
/* MCU Specific Definitions */
#define TC397
#define CPU_FREQUENCY 300000000U /* 300 MHz */
#define PERIPHERAL_FREQUENCY 150000000U /* 150 MHz */
#define STM_FREQUENCY 100000000U /* 100 MHz */
/* Peripheral Base Addresses */
#define CAN0_BASE 0xF0200000U
#define CAN1_BASE 0xF0210000U
#define CAN2_BASE 0xF0220000U
#define CAN3_BASE 0xF0230000U
#define ASCLIN0_BASE 0xF0000000U
#define ASCLIN1_BASE 0xF0000100U
#define ASCLIN2_BASE 0xF0000200U
#define ASCLIN3_BASE 0xF0000300U
#define QSPI0_BASE 0xF0001000U
#define QSPI1_BASE 0xF0001100U
#define QSPI2_BASE 0xF0001200U
#define QSPI3_BASE 0xF0001300U
#define I2C0_BASE 0xF0002000U
#define I2C1_BASE 0xF0002100U
#define VADC0_BASE 0xF0020000U
#define VADC1_BASE 0xF0020100U
#define GTM_BASE 0xF0100000U
#define GPT12_BASE 0xF0003000U
/* Interrupt Priorities */
#define CAN0_IRQ_PRIORITY 5
#define CAN1_IRQ_PRIORITY 5
#define ASCLIN0_IRQ_PRIORITY 6
#define QSPI0_IRQ_PRIORITY 7
#define I2C0_IRQ_PRIORITY 7
#define VADC0_IRQ_PRIORITY 8
#define GTM_IRQ_PRIORITY 8
/* DMA Configuration */
#define DMA_CHANNEL_COUNT 128
#define DMA_PRIORITY_HIGH 0
#define DMA_PRIORITY_MEDIUM 1
#define DMA_PRIORITY_LOW 2
/* Safety Features */
#define ENABLE_SAFETY_WATCHDOG 1
#define WATCHDOG_TIMEOUT_MS 100
#define ENABLE_ECC 1
#define ENABLE_MEMORY_PROTECTION 1
/* Memory Configuration */
#define FLASH_SIZE 0x800000U /* 8 MB */
#define RAM_SIZE 0x280000U /* 2.5 MB */
#define DSPR_SIZE 0x20000U /* 128 KB per CPU */
/* CAN FD Configuration */
#define CAN_FD_ENABLED 1
#define CAN_FD_MAX_PAYLOAD 64
#define CAN_TX_FIFO_SIZE 32
#define CAN_RX_FIFO_SIZE 64
#endif /* TC3XX_CONFIG_H */
@@ -0,0 +1,132 @@
/**
* @file tc3xx_hal.c
* @brief Infineon TriCore TC3xx Hardware Abstraction Layer
*/
#include "tc3xx_config.h"
#include "can_driver.h"
#include "uart_driver.h"
#include "spi_driver.h"
#include "i2c_driver.h"
#include "gpio_driver.h"
#include "adc_driver.h"
#include "pwm_driver.h"
#include "Ifx_Types.h"
#include "IfxCan_Can.h"
#include "IfxAsclin_Asc.h"
#include "IfxQspi_SpiMaster.h"
#include "IfxI2c_I2c.h"
#include "IfxPort.h"
#include "IfxVadc_Adc.h"
#include "IfxGtm_Tom_PwmHl.h"
/* CAN HAL Implementation */
int hal_can_init(uint32_t baudrate, uint8_t frame_type, bool enable_fd) {
/* Create CAN module configuration */
IfxCan_Can_Config canConfig;
IfxCan_Can_initModuleConfig(&canConfig, &MODULE_CAN0);
/* Configure node */
canConfig.nodeConfig[0].baudRate.baudrate = baudrate;
canConfig.nodeConfig[0].frame.type = IfxCan_FrameType_receive;
if (enable_fd) {
canConfig.nodeConfig[0].frame.mode = IfxCan_FrameMode_fd;
}
/* Initialize CAN module */
IfxCan_Can_initModule(&g_canDriver, &canConfig);
/* Configure TX FIFO */
IfxCan_Can_initTxFifo(&g_canDriver, &g_canTxFifo);
/* Configure RX FIFO */
IfxCan_Can_initRxFifo(&g_canDriver, &g_canRxFifo);
/* Enable interrupts */
IfxCan_Can_enableInterrupt(&g_canDriver, IfxCan_Interrupt_messageStoredToDedicatedRxFifo);
return 0;
}
int hal_can_send_message(const CanMessage_t* message, uint32_t* mailbox) {
/* Create TX message */
IfxCan_Can_Message txMessage;
/* Set message ID */
txMessage.messageId = message->id.id;
txMessage.extendedFrame = message->id.is_extended;
/* Set data */
txMessage.dataLengthCode = message->length;
for (int i = 0; i < message->length; i++) {
txMessage.data[i] = message->data[i];
}
/* Send message */
if (IfxCan_Can_sendMessage(&g_canDriver, &txMessage, &txMessage.messageId)
!= IfxCan_Status_ok) {
return -1;
}
*mailbox = 0;
return 0;
}
int hal_can_receive_message(CanMessage_t* message) {
/* Create RX message */
IfxCan_Can_Message rxMessage;
/* Receive message */
if (IfxCan_Can_readMessage(&g_canDriver, &rxMessage, &rxMessage.messageId)
!= IfxCan_Status_ok) {
return -1;
}
/* Copy message data */
message->id.id = rxMessage.messageId;
message->id.is_extended = rxMessage.extendedFrame;
message->length = rxMessage.dataLengthCode;
for (int i = 0; i < message->length; i++) {
message->data[i] = rxMessage.data[i];
}
return 0;
}
/* GPIO HAL Implementation */
void hal_gpio_init(uint8_t port, uint8_t pin, GpioMode_t mode) {
/* Configure port pin */
IfxPort_setPinMode(&MODULE_P00, pin, IfxPort_Mode_outputPushPullGeneral);
}
void hal_gpio_write(uint8_t port, uint8_t pin, bool value) {
if (value) {
IfxPort_setPinHigh(&MODULE_P00, pin);
} else {
IfxPort_setPinLow(&MODULE_P00, pin);
}
}
bool hal_gpio_read(uint8_t port, uint8_t pin) {
return IfxPort_getPinState(&MODULE_P00, pin);
}
/* UART HAL Implementation */
int hal_uart_init(uint8_t instance, UartConfig_t* config) {
/* Create ASCLIN configuration */
IfxAsclin_Asc_Config ascConfig;
IfxAsclin_Asc_initModuleConfig(&ascConfig, &MODULE_ASCLIN0);
/* Configure baudrate */
ascConfig.baudrate.baudrate = config->baudrate;
/* Configure pins */
ascConfig.pins = &g_ascPins;
/* Initialize module */
IfxAsclin_Asc_initModule(&g_ascDriver, &ascConfig);
return 0;
}
@@ -0,0 +1,89 @@
/**
* @file s32k14x_config.h
* @brief NXP S32K14x specific configuration
*/
#ifndef S32K14X_CONFIG_H
#define S32K14X_CONFIG_H
/* MCU Specific Definitions */
#define S32K144
#define CPU_FREQUENCY 160000000U /* 160 MHz */
#define BUS_FREQUENCY 40000000U /* 40 MHz */
#define SLOW_FREQUENCY 10000000U /* 10 MHz */
/* Peripheral Base Addresses */
#define GPIOA_BASE 0x400FF000U
#define GPIOB_BASE 0x400FF040U
#define GPIOC_BASE 0x400FF080U
#define GPIOD_BASE 0x400FF0C0U
#define GPIOE_BASE 0x400FF100U
#define LPUART0_BASE 0x4006A000U
#define LPUART1_BASE 0x4006B000U
#define LPUART2_BASE 0x4006C000U
#define LPSPI0_BASE 0x4002C000U
#define LPSPI1_BASE 0x4002D000U
#define LPSPI2_BASE 0x4002E000U
#define LPI2C0_BASE 0x40066000U
#define LPI2C1_BASE 0x40067000U
#define ADC0_BASE 0x4003B000U
#define ADC1_BASE 0x4003C000U
#define FTM0_BASE 0x40038000U
#define FTM1_BASE 0x40039000U
#define FTM2_BASE 0x4003A000U
#define FTM3_BASE 0x40026000U
#define FTM4_BASE 0x40027000U
#define FLEXCAN0_BASE 0x40024000U
#define FLEXCAN1_BASE 0x40025000U
#define FLEXCAN2_BASE 0x4002B000U
/* Clock Configuration */
#define SOSC_FREQUENCY 8000000U /* System oscillator */
#define SPLL_FREQUENCY 160000000U /* System PLL */
#define FIRC_FREQUENCY 48000000U /* Fast IRC */
#define SIRC_FREQUENCY 8000000U /* Slow IRC */
/* Peripheral Clock Configuration */
#define FLEXCAN0_CLOCK 40000000U /* 40 MHz */
#define FLEXCAN1_CLOCK 40000000U
#define LPUART0_CLOCK 40000000U
#define LPSPI0_CLOCK 40000000U
#define LPI2C0_CLOCK 40000000U
#define ADC0_CLOCK 40000000U
#define FTM0_CLOCK 40000000U
/* NVIC Priority Configuration */
#define FLEXCAN0_IRQ_PRIORITY 5
#define FLEXCAN1_IRQ_PRIORITY 5
#define LPUART0_IRQ_PRIORITY 6
#define LPUART1_IRQ_PRIORITY 6
#define LPSPI0_IRQ_PRIORITY 7
#define LPI2C0_IRQ_PRIORITY 7
#define ADC0_IRQ_PRIORITY 8
#define FTM0_IRQ_PRIORITY 8
/* DMA Configuration */
#define DMA_CHANNEL_COUNT 16
#define DMA_MUX_CHANNEL_COUNT 16
/* Safety Features */
#define ENABLE_CLOCK_MONITORING 1
#define ENABLE_MEMORY_PROTECTION 1
#define WATCHDOG_TIMEOUT_MS 100
/* Memory Configuration */
#define FLASH_SIZE 0x100000U /* 1 MB */
#define RAM_SIZE 0x20000U /* 128 KB */
#define EEPROM_SIZE 0x1000U /* 4 KB */
/* CAN FD Configuration */
#define CAN_FD_ENABLED 1
#define CAN_FD_MAX_PAYLOAD 64
#endif /* S32K14X_CONFIG_H */
+224
View File
@@ -0,0 +1,224 @@
/**
* @file s32k14x_hal.c
* @brief NXP S32K14x Hardware Abstraction Layer
*/
#include "s32k14x_config.h"
#include "can_driver.h"
#include "uart_driver.h"
#include "spi_driver.h"
#include "i2c_driver.h"
#include "gpio_driver.h"
#include "adc_driver.h"
#include "pwm_driver.h"
#include "S32K144.h"
/* CAN HAL Implementation */
int hal_can_init(uint32_t baudrate, uint8_t frame_type, bool enable_fd) {
/* Enable FLEXCAN0 clock */
PCC->PCCn[PCC_FlexCAN0_INDEX] |= PCC_PCCn_CGC_MASK;
/* Configure CAN pins */
// PTE4 - CAN0_RX, PTE5 - CAN0_TX
PCC->PCCn[PCC_PORTE_INDEX] |= PCC_PCCn_CGC_MASK;
PORTE->PCR[4] = PORT_PCR_MUX(5); /* CAN0_RX */
PORTE->PCR[5] = PORT_PCR_MUX(5); /* CAN0_TX */
/* Reset FLEXCAN */
CAN0->MCR |= CAN_MCR_SOFTRST_MASK;
while (CAN0->MCR & CAN_MCR_SOFTRST_MASK);
/* Configure for CAN FD if enabled */
if (enable_fd) {
CAN0->MCR |= CAN_MCR_FDEN_MASK; /* Enable FD */
}
/* Set baudrate */
uint32_t prescaler = BUS_FREQUENCY / (baudrate * 10); /* 10 time quanta */
CAN0->CTRL1 = CAN_CTRL1_PRESDIV(prescaler - 1) |
CAN_CTRL1_PSEG1(3) |
CAN_CTRL1_PSEG2(2) |
CAN_CTRL1_PROPSEG(4);
/* Configure message buffers */
CAN0->RXMGMASK = 0x1FFFFFFF; /* Accept all IDs */
CAN0->RX14MASK = 0x1FFFFFFF;
CAN0->RX15MASK = 0x1FFFFFFF;
/* Enable interrupts */
CAN0->IMASK1 |= CAN_IMASK1_BUF31TO0M_MASK;
CAN0->MCR |= CAN_MCR_IRMQ_MASK; /* Individual RX masking */
/* Normal mode */
CAN0->MCR &= ~CAN_MCR_HALT_MASK;
while (CAN0->MCR & CAN_MCR_FRZACK_MASK);
return 0;
}
int hal_can_send_message(const CanMessage_t* message, uint32_t* mailbox) {
/* Find free message buffer */
*mailbox = 0;
while (*mailbox < 32) {
if ((CAN0->IFLAG1 & (1 << *mailbox)) != 0) {
break;
}
(*mailbox)++;
}
if (*mailbox >= 32) {
return -1;
}
/* Configure message buffer */
CAN0->RAMn[*mailbox * 4 + 1] = (message->id.id << 18) |
(message->id.is_extended ? 1 << 29 : 0) |
(message->length << 16);
/* Copy data */
for (int i = 0; i < message->length; i += 4) {
uint32_t data = 0;
for (int j = 0; j < 4 && (i + j) < message->length; j++) {
data |= (message->data[i + j] << (j * 8));
}
CAN0->RAMn[*mailbox * 4 + 2 + (i / 4)] = data;
}
/* Enable transmission */
CAN0->RAMn[*mailbox * 4] = CAN_WORD0_IDE_MASK |
CAN_WORD0_SRR_MASK |
CAN_WORD0_ESI_MASK |
CAN_WORD0_CODE(0xC); /* TX data */
return 0;
}
int hal_can_receive_message(CanMessage_t* message) {
/* Check for received messages */
uint32_t iflag = CAN0->IFLAG1;
if (iflag == 0) {
return -1;
}
/* Find received message buffer */
uint32_t mailbox = 0;
while (mailbox < 32) {
if (iflag & (1 << mailbox)) {
break;
}
mailbox++;
}
if (mailbox >= 32) {
return -1;
}
/* Read message */
uint32_t word0 = CAN0->RAMn[mailbox * 4];
uint32_t word1 = CAN0->RAMn[mailbox * 4 + 1];
/* Check if RX buffer */
if ((word0 & CAN_WORD0_CODE_MASK) != CAN_WORD0_CODE(0x4)) {
CAN0->IFLAG1 = (1 << mailbox); /* Clear flag */
return -1;
}
/* Get ID */
message->id.is_extended = (word0 & CAN_WORD0_IDE_MASK) != 0;
if (message->id.is_extended) {
message->id.id = (word0 & CAN_WORD0_ID_MASK) >> 0;
} else {
message->id.id = (word0 & CAN_WORD0_ID_MASK) >> 18;
}
/* Get data length */
message->length = (word1 & CAN_WORD1_DLC_MASK) >> 16;
/* Get data */
for (int i = 0; i < message->length; i += 4) {
uint32_t data = CAN0->RAMn[mailbox * 4 + 2 + (i / 4)];
for (int j = 0; j < 4 && (i + j) < message->length; j++) {
message->data[i + j] = (data >> (j * 8)) & 0xFF;
}
}
/* Clear flag */
CAN0->IFLAG1 = (1 << mailbox);
return 0;
}
/* GPIO HAL Implementation */
void hal_gpio_init(uint8_t port, uint8_t pin, GpioMode_t mode) {
GPIO_Type* gpio_port = get_gpio_port(port);
PORT_Type* port_config = get_port_config(port);
if (gpio_port == NULL || port_config == NULL) {
return;
}
/* Enable clock */
PCC->PCCn[PCC_PORTA_INDEX + port] |= PCC_PCCn_CGC_MASK;
PCC->PCCn[PCC_GPIOA_INDEX + port] |= PCC_PCCn_CGC_MASK;
/* Configure pin mux */
switch (mode) {
case GPIO_MODE_INPUT:
port_config->PCR[pin] = PORT_PCR_MUX(1);
gpio_port->PDDR &= ~(1 << pin);
break;
case GPIO_MODE_OUTPUT:
port_config->PCR[pin] = PORT_PCR_MUX(1);
gpio_port->PDDR |= (1 << pin);
break;
default:
break;
}
}
void hal_gpio_write(uint8_t port, uint8_t pin, bool value) {
GPIO_Type* gpio_port = get_gpio_port(port);
if (gpio_port == NULL) {
return;
}
if (value) {
gpio_port->PSOR = (1 << pin);
} else {
gpio_port->PCOR = (1 << pin);
}
}
bool hal_gpio_read(uint8_t port, uint8_t pin) {
GPIO_Type* gpio_port = get_gpio_port(port);
if (gpio_port == NULL) {
return false;
}
return (gpio_port->PDIR & (1 << pin)) != 0;
}
/* Helper functions */
static GPIO_Type* get_gpio_port(uint8_t port) {
switch (port) {
case 0: return PTA;
case 1: return PTB;
case 2: return PTC;
case 3: return PTD;
case 4: return PTE;
default: return NULL;
}
}
static PORT_Type* get_port_config(uint8_t port) {
switch (port) {
case 0: return PORTA;
case 1: return PORTB;
case 2: return PORTC;
case 3: return PORTD;
case 4: return PORTE;
default: return NULL;
}
}
@@ -0,0 +1,126 @@
/**
* @file stm32f4xx_config.h
* @brief STM32F4 specific configuration
*/
#ifndef STM32F4XX_CONFIG_H
#define STM32F4XX_CONFIG_H
/* MCU Specific Definitions */
#define STM32F407xx
#define HSE_VALUE 8000000U /* External crystal */
#define HSI_VALUE 16000000U /* Internal oscillator */
#define LSE_VALUE 32768U /* Low speed external */
#define LSI_VALUE 32000U /* Low speed internal */
/* Clock Configuration */
#define SYSTEM_CLOCK 168000000U /* 168 MHz */
#define AHB_CLOCK 168000000U
#define APB1_CLOCK 42000000U /* 42 MHz */
#define APB2_CLOCK 84000000U /* 84 MHz */
/* Peripheral Base Addresses */
#define GPIOA_BASE 0x40020000U
#define GPIOB_BASE 0x40020400U
#define GPIOC_BASE 0x40020800U
#define GPIOD_BASE 0x40020C00U
#define GPIOE_BASE 0x40021000U
#define GPIOF_BASE 0x40021400U
#define GPIOG_BASE 0x40021800U
#define GPIOH_BASE 0x40021C00U
#define USART1_BASE 0x40011000U
#define USART2_BASE 0x40004400U
#define USART3_BASE 0x40004800U
#define UART4_BASE 0x40004C00U
#define UART5_BASE 0x40005000U
#define USART6_BASE 0x40011400U
#define SPI1_BASE 0x40013000U
#define SPI2_BASE 0x40003800U
#define SPI3_BASE 0x40003C00U
#define I2C1_BASE 0x40005400U
#define I2C2_BASE 0x40005800U
#define I2C3_BASE 0x40005C00U
#define ADC1_BASE 0x40012000U
#define ADC2_BASE 0x40012100U
#define ADC3_BASE 0x40012200U
#define TIM1_BASE 0x40010000U
#define TIM2_BASE 0x40000000U
#define TIM3_BASE 0x40000400U
#define TIM4_BASE 0x40000800U
#define TIM5_BASE 0x40000C00U
#define TIM8_BASE 0x40010400U
#define TIM9_BASE 0x40014000U
#define TIM10_BASE 0x40014400U
#define TIM11_BASE 0x40014800U
#define TIM12_BASE 0x40001800U
#define TIM13_BASE 0x40001C00U
#define TIM14_BASE 0x40002000U
#define CAN1_BASE 0x40006400U
#define CAN2_BASE 0x40006800U
/* NVIC Priority Configuration */
#define CAN1_IRQ_PRIORITY 5
#define CAN2_IRQ_PRIORITY 5
#define USART1_IRQ_PRIORITY 6
#define USART2_IRQ_PRIORITY 6
#define USART3_IRQ_PRIORITY 6
#define SPI1_IRQ_PRIORITY 7
#define SPI2_IRQ_PRIORITY 7
#define I2C1_IRQ_PRIORITY 7
#define I2C2_IRQ_PRIORITY 7
#define ADC_IRQ_PRIORITY 8
#define TIM_IRQ_PRIORITY 8
/* DMA Configuration */
#define DMA1_STREAM0_CHANNEL 0
#define DMA1_STREAM1_CHANNEL 1
#define DMA1_STREAM2_CHANNEL 2
#define DMA1_STREAM3_CHANNEL 3
#define DMA1_STREAM4_CHANNEL 4
#define DMA1_STREAM5_CHANNEL 5
#define DMA1_STREAM6_CHANNEL 6
#define DMA1_STREAM7_CHANNEL 7
#define DMA2_STREAM0_CHANNEL 0
#define DMA2_STREAM1_CHANNEL 1
#define DMA2_STREAM2_CHANNEL 2
#define DMA2_STREAM3_CHANNEL 3
#define DMA2_STREAM4_CHANNEL 4
#define DMA2_STREAM5_CHANNEL 5
#define DMA2_STREAM6_CHANNEL 6
#define DMA2_STREAM7_CHANNEL 7
/* GPIO Alternate Function Mapping */
#define GPIO_AF_UART1_TX 7
#define GPIO_AF_UART1_RX 7
#define GPIO_AF_UART2_TX 7
#define GPIO_AF_UART2_RX 7
#define GPIO_AF_SPI1_SCK 5
#define GPIO_AF_SPI1_MOSI 5
#define GPIO_AF_SPI1_MISO 5
#define GPIO_AF_I2C1_SCL 4
#define GPIO_AF_I2C1_SDA 4
#define GPIO_AF_CAN1_TX 9
#define GPIO_AF_CAN1_RX 9
#define GPIO_AF_TIM1_CH1 1
#define GPIO_AF_TIM1_CH2 1
#define GPIO_AF_TIM1_CH3 1
#define GPIO_AF_TIM1_CH4 1
/* Memory Configuration */
#define FLASH_SIZE 0x100000U /* 1 MB */
#define RAM_SIZE 0x20000U /* 128 KB */
#define CCM_RAM_SIZE 0x10000U /* 64 KB */
/* Safety Features */
#define ENABLE_CLOCK_SECURITY_SYSTEM 1
#define ENABLE_BROWN_OUT_RESET 1
#define BROWNOUT_THRESHOLD 0x08 /* 2.7V */
#endif /* STM32F4XX_CONFIG_H */
@@ -0,0 +1,289 @@
/**
* @file stm32f4xx_hal.c
* @brief STM32F4 Hardware Abstraction Layer
*/
#include "stm32f4xx_config.h"
#include "can_driver.h"
#include "uart_driver.h"
#include "spi_driver.h"
#include "i2c_driver.h"
#include "gpio_driver.h"
#include "adc_driver.h"
#include "pwm_driver.h"
#include "stm32f4xx.h"
/* CAN HAL Implementation */
int hal_can_init(uint32_t baudrate, uint8_t frame_type, bool enable_fd) {
/* Enable CAN clock */
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
/* Configure CAN GPIO */
// PB8 - CAN1_RX, PB9 - CAN1_TX
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
GPIOB->MODER |= (GPIO_MODER_MODER8_1 | GPIO_MODER_MODER9_1);
GPIOB->OTYPER &= ~(GPIO_OTYPER_OT_8 | GPIO_OTYPER_OT_9);
GPIOB->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR8 | GPIO_OSPEEDER_OSPEEDR9);
GPIOB->AFR[1] |= (9 << 0) | (9 << 4); /* AF9 for CAN */
/* Reset CAN */
CAN1->MCR |= CAN_MCR_RESET;
CAN1->MCR &= ~CAN_MCR_RESET;
/* Exit sleep mode */
CAN1->MCR &= ~CAN_MCR_SLEEP;
/* Set baudrate */
uint32_t prescaler = 0;
uint32_t time_quantum = 0;
switch (baudrate) {
case 125000:
prescaler = 21;
time_quantum = 16;
break;
case 250000:
prescaler = 11;
time_quantum = 15;
break;
case 500000:
prescaler = 5;
time_quantum = 16;
break;
case 1000000:
prescaler = 3;
time_quantum = 14;
break;
default:
return -1;
}
CAN1->BTR = ((prescaler - 1) << 20) |
((time_quantum - 1) << 16) |
(3 << 20) | /* SJW = 4 */
(7 << 16); /* BS1 = 8 */
/* Configure filters */
CAN1->FMR |= CAN_FMR_FINIT;
CAN1->FM1R &= ~CAN_FM1R_FBM0; /* Mask mode for filter 0 */
CAN1->FS1R |= CAN_FS1R_FSC0; /* 32-bit scale */
CAN1->FFA1R &= ~CAN_FFA1R_FFA0; /* FIFO 0 */
CAN1->FMR &= ~CAN_FMR_FINIT;
/* Enable interrupts */
CAN1->IER |= CAN_IER_FMPIE0 | /* FIFO 0 message pending */
CAN_IER_TMEIE | /* Transmit mailbox empty */
CAN_IER_BOFIE | /* Bus-off */
CAN_IER_ERRIE; /* Error */
/* Normal mode */
CAN1->MCR &= ~CAN_MCR_SLEEP;
return 0;
}
int hal_can_send_message(const CanMessage_t* message, uint32_t* mailbox) {
/* Check for free mailbox */
if ((CAN1->TSR & CAN_TSR_TME0) != 0) {
*mailbox = 0;
} else if ((CAN1->TSR & CAN_TSR_TME1) != 0) {
*mailbox = 1;
} else if ((CAN1->TSR & CAN_TSR_TME2) != 0) {
*mailbox = 2;
} else {
return -1;
}
/* Configure mailbox */
CAN_TxMailBox_TypeDef* tx_mailbox = &CAN1->sTxMailBox[*mailbox];
/* Set ID */
if (message->id.is_extended) {
tx_mailbox->TIR = (message->id.id << 3) | CAN_TI0R_IDE;
} else {
tx_mailbox->TIR = (message->id.id << 21);
}
/* Set data length and data */
tx_mailbox->TDTR = message->length;
/* Copy data */
uint32_t data[2] = {0, 0};
for (int i = 0; i < message->length; i++) {
if (i < 4) {
data[0] |= (message->data[i] << (i * 8));
} else {
data[1] |= (message->data[i] << ((i - 4) * 8));
}
}
tx_mailbox->TDLR = data[0];
tx_mailbox->TDHR = data[1];
/* Request transmission */
tx_mailbox->TIR |= CAN_TI0R_TXRQ;
return 0;
}
int hal_can_receive_message(CanMessage_t* message) {
/* Check if message available */
if ((CAN1->RF0R & CAN_RF0R_FMP0) == 0) {
return -1;
}
/* Get message */
CAN_FIFOMailBox_TypeDef* rx_mailbox = &CAN1->sFIFOMailBox[0];
/* Get ID */
if (rx_mailbox->RIR & CAN_RI0R_IDE) {
message->id.is_extended = true;
message->id.id = (rx_mailbox->RIR >> 3) & 0x1FFFFFFF;
} else {
message->id.is_extended = false;
message->id.id = (rx_mailbox->RIR >> 21) & 0x7FF;
}
/* Get data length */
message->length = rx_mailbox->RDTR & CAN_RDT0R_DLC;
/* Get data */
uint32_t data_low = rx_mailbox->RDLR;
uint32_t data_high = rx_mailbox->RDHR;
for (int i = 0; i < message->length; i++) {
if (i < 4) {
message->data[i] = (data_low >> (i * 8)) & 0xFF;
} else {
message->data[i] = (data_high >> ((i - 4) * 8)) & 0xFF;
}
}
/* Release FIFO */
CAN1->RF0R |= CAN_RF0R_RFOM0;
return 0;
}
/* GPIO HAL Implementation */
void hal_gpio_init(uint8_t port, uint8_t pin, GpioMode_t mode) {
GPIO_TypeDef* gpio_port = get_gpio_port(port);
if (gpio_port == NULL) {
return;
}
/* Enable GPIO clock */
RCC->AHB1ENR |= (1 << port);
/* Configure mode */
uint32_t moder_value = 0;
switch (mode) {
case GPIO_MODE_INPUT:
moder_value = 0x00;
break;
case GPIO_MODE_OUTPUT:
moder_value = 0x01;
break;
case GPIO_MODE_ALTERNATE:
moder_value = 0x02;
break;
case GPIO_MODE_ANALOG:
moder_value = 0x03;
break;
}
gpio_port->MODER &= ~(0x03 << (pin * 2));
gpio_port->MODER |= (moder_value << (pin * 2));
}
void hal_gpio_write(uint8_t port, uint8_t pin, bool value) {
GPIO_TypeDef* gpio_port = get_gpio_port(port);
if (gpio_port == NULL) {
return;
}
if (value) {
gpio_port->BSRR = (1 << pin);
} else {
gpio_port->BSRR = (1 << (pin + 16));
}
}
bool hal_gpio_read(uint8_t port, uint8_t pin) {
GPIO_TypeDef* gpio_port = get_gpio_port(port);
if (gpio_port == NULL) {
return false;
}
return (gpio_port->IDR & (1 << pin)) != 0;
}
/* UART HAL Implementation */
int hal_uart_init(uint8_t instance, UartConfig_t* config) {
USART_TypeDef* uart = get_uart_instance(instance);
if (uart == NULL) {
return -1;
}
/* Enable clock */
if (instance == 0) {
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
} else {
RCC->APB1ENR |= (RCC_APB1ENR_USART2EN << (instance - 1));
}
/* Configure baudrate */
uint32_t clock = (instance == 0 || instance == 5) ? APB2_CLOCK : APB1_CLOCK;
uart->BRR = clock / config->baudrate;
/* Configure control registers */
uart->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
if (config->data_bits == UART_DATA_BITS_9) {
uart->CR1 |= USART_CR1_M;
}
uart->CR2 = 0;
if (config->stop_bits == UART_STOP_BITS_2) {
uart->CR2 |= USART_CR2_STOP_1;
}
/* Enable interrupts */
if (config->enable_rx) {
uart->CR1 |= USART_CR1_RXNEIE;
}
return 0;
}
/* Helper functions */
static GPIO_TypeDef* get_gpio_port(uint8_t port) {
switch (port) {
case 0: return GPIOA;
case 1: return GPIOB;
case 2: return GPIOC;
case 3: return GPIOD;
case 4: return GPIOE;
case 5: return GPIOF;
case 6: return GPIOG;
case 7: return GPIOH;
default: return NULL;
}
}
static USART_TypeDef* get_uart_instance(uint8_t instance) {
switch (instance) {
case 0: return USART1;
case 1: return USART2;
case 2: return USART3;
case 3: return UART4;
case 4: return UART5;
case 5: return USART6;
default: return NULL;
}
}
+283
View File
@@ -0,0 +1,283 @@
/**
* @file adc_driver.c
* @brief ADC driver implementation
*/
#include "adc_driver.h"
#include "isr.h"
#include <string.h>
/* ADC Driver State */
typedef struct {
bool initialized;
AdcConfig_t config;
AdcStatistics_t statistics;
uint16_t conversion_buffer[ADC_MAX_CHANNELS];
uint8_t current_channel;
bool conversion_active;
bool dma_active;
uint16_t* dma_buffer;
uint16_t dma_length;
uint16_t dma_index;
Semaphore_t conversion_semaphore;
Mutex_t conversion_mutex;
} AdcDriverState_t;
static AdcDriverState_t adc_drivers[ADC_MAX_INSTANCES];
/* Initialize ADC Driver */
KernelStatus_t adc_init(uint8_t instance, AdcConfig_t* config) {
if (instance >= ADC_MAX_INSTANCES || config == NULL) {
return KERNEL_INVALID_PARAMETER;
}
AdcDriverState_t* driver = &adc_drivers[instance];
if (driver->initialized) {
return KERNEL_ERROR;
}
/* Copy configuration */
memcpy(&driver->config, config, sizeof(AdcConfig_t));
/* Initialize state */
memset(&driver->statistics, 0, sizeof(AdcStatistics_t));
driver->current_channel = 0;
driver->conversion_active = false;
driver->dma_active = false;
driver->dma_buffer = NULL;
driver->dma_length = 0;
driver->dma_index = 0;
/* Create synchronization primitives */
semaphore_create(&driver->conversion_semaphore, SEMAPHORE_BINARY, 0, 1);
mutex_create(&driver->conversion_mutex, false);
/* Initialize ADC hardware */
if (hal_adc_init(instance, config) != 0) {
return KERNEL_ERROR;
}
/* Enable interrupts */
hal_adc_enable_interrupts(instance);
driver->initialized = true;
return KERNEL_OK;
}
/* Start ADC Conversion */
KernelStatus_t adc_start_conversion(uint8_t instance) {
if (instance >= ADC_MAX_INSTANCES) {
return KERNEL_INVALID_PARAMETER;
}
AdcDriverState_t* driver = &adc_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
if (driver->conversion_active) {
return KERNEL_RESOURCE_BUSY;
}
/* Reset conversion state */
driver->current_channel = 0;
driver->conversion_active = true;
/* Start conversion */
hal_adc_start_conversion(instance);
return KERNEL_OK;
}
/* Stop ADC Conversion */
KernelStatus_t adc_stop_conversion(uint8_t instance) {
if (instance >= ADC_MAX_INSTANCES) {
return KERNEL_INVALID_PARAMETER;
}
AdcDriverState_t* driver = &adc_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
hal_adc_stop_conversion(instance);
driver->conversion_active = false;
return KERNEL_OK;
}
/* Read ADC Channel */
KernelStatus_t adc_read_channel(uint8_t instance, uint8_t channel, uint16_t* value,
uint32_t timeout_ms) {
if (instance >= ADC_MAX_INSTANCES || value == NULL) {
return KERNEL_INVALID_PARAMETER;
}
AdcDriverState_t* driver = &adc_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
/* Lock conversion mutex */
if (mutex_lock(&driver->conversion_mutex, timeout_ms) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Configure single channel conversion */
hal_adc_configure_channel(instance, channel);
/* Start conversion */
hal_adc_start_single_conversion(instance, channel);
/* Wait for conversion complete */
if (semaphore_take(&driver->conversion_semaphore, timeout_ms) != KERNEL_OK) {
mutex_unlock(&driver->conversion_mutex);
return KERNEL_TIMEOUT;
}
/* Read value */
*value = hal_adc_read_value(instance, channel);
/* Update statistics */
driver->statistics.conversions_completed++;
/* Unlock */
mutex_unlock(&driver->conversion_mutex);
return KERNEL_OK;
}
/* Read Multiple ADC Channels */
KernelStatus_t adc_read_channels(uint8_t instance, uint16_t* values, uint8_t count,
uint32_t timeout_ms) {
if (instance >= ADC_MAX_INSTANCES || values == NULL || count == 0) {
return KERNEL_INVALID_PARAMETER;
}
AdcDriverState_t* driver = &adc_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
/* Start conversion */
if (adc_start_conversion(instance) != KERNEL_OK) {
return KERNEL_ERROR;
}
/* Wait for all channels */
if (semaphore_take(&driver->conversion_semaphore, timeout_ms) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Copy values */
memcpy(values, driver->conversion_buffer, count * sizeof(uint16_t));
return KERNEL_OK;
}
/* Start DMA Conversion */
KernelStatus_t adc_start_dma(uint8_t instance, uint16_t* buffer, uint16_t length) {
if (instance >= ADC_MAX_INSTANCES || buffer == NULL || length == 0) {
return KERNEL_INVALID_PARAMETER;
}
AdcDriverState_t* driver = &adc_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
if (driver->dma_active) {
return KERNEL_RESOURCE_BUSY;
}
/* Configure DMA */
driver->dma_buffer = buffer;
driver->dma_length = length;
driver->dma_index = 0;
driver->dma_active = true;
/* Start DMA conversion */
hal_adc_start_dma(instance, buffer, length);
return KERNEL_OK;
}
/* ADC Interrupt Handler */
void adc_process_interrupt(uint8_t instance) {
if (instance >= ADC_MAX_INSTANCES) {
return;
}
AdcDriverState_t* driver = &adc_drivers[instance];
if (!driver->initialized) {
return;
}
uint32_t interrupt_status = hal_adc_get_interrupt_status(instance);
/* Handle conversion complete */
if (interrupt_status & ADC_INTERRUPT_CONVERSION_COMPLETE) {
if (driver->conversion_active) {
/* Store converted value */
uint16_t value = hal_adc_read_current_value(instance);
if (driver->current_channel < ADC_MAX_CHANNELS) {
driver->conversion_buffer[driver->current_channel] = value;
driver->current_channel++;
}
/* Check if all channels converted */
if (driver->current_channel >= driver->config.channel_count) {
driver->conversion_active = false;
/* Call callback */
if (driver->config.conversion_complete_callback != NULL) {
driver->config.conversion_complete_callback(
driver->conversion_buffer,
driver->config.channel_count);
}
/* Signal conversion complete */
semaphore_give(&driver->conversion_semaphore);
} else {
/* Start next channel conversion */
hal_adc_start_channel_conversion(instance,
driver->config.channels[driver->current_channel].channel);
}
}
}
/* Handle DMA complete */
if (interrupt_status & ADC_INTERRUPT_DMA_COMPLETE) {
driver->dma_active = false;
driver->statistics.dma_transfers++;
}
/* Handle watchdog */
if (interrupt_status & ADC_INTERRUPT_WATCHDOG) {
driver->statistics.watchdog_events++;
}
/* Handle errors */
if (interrupt_status & ADC_INTERRUPT_ERROR) {
driver->statistics.conversions_failed++;
driver->statistics.overrun_errors++;
}
/* Clear interrupt flags */
hal_adc_clear_interrupts(instance, interrupt_status);
}
/* Convert ADC Value to Voltage */
float adc_convert_to_voltage(uint16_t adc_value, AdcResolution_t resolution,
float reference_voltage) {
uint32_t max_value = (1 << resolution) - 1;
return ((float)adc_value / (float)max_value) * reference_voltage;
}
+228
View File
@@ -0,0 +1,228 @@
/**
* @file can_driver.c
* @brief CAN driver implementation
*/
#include "can_driver.h"
#include "isr.h"
#include <string.h>
/* CAN Driver State */
typedef struct {
bool initialized;
CanConfig_t config;
CanStatistics_t statistics;
CanMessage_t rx_fifo[CAN_MAX_RX_FIFO_DEPTH];
uint8_t rx_head;
uint8_t rx_tail;
uint8_t rx_count;
Semaphore_t rx_semaphore;
Semaphore_t tx_semaphore;
Mutex_t tx_mutex;
bool bus_off;
} CanDriverState_t;
static CanDriverState_t can_driver;
/* Initialize CAN Driver */
KernelStatus_t can_init(CanConfig_t* config) {
if (config == NULL || can_driver.initialized) {
return KERNEL_ERROR;
}
/* Copy configuration */
memcpy(&can_driver.config, config, sizeof(CanConfig_t));
/* Initialize state */
memset(&can_driver.statistics, 0, sizeof(CanStatistics_t));
can_driver.rx_head = 0;
can_driver.rx_tail = 0;
can_driver.rx_count = 0;
can_driver.bus_off = false;
/* Create synchronization primitives */
semaphore_create(&can_driver.rx_semaphore, SEMAPHORE_COUNTING, 0,
CAN_MAX_RX_FIFO_DEPTH);
semaphore_create(&can_driver.tx_semaphore, SEMAPHORE_COUNTING,
CAN_MAX_TX_MAILBOXES, CAN_MAX_TX_MAILBOXES);
mutex_create(&can_driver.tx_mutex, false);
/* Configure CAN hardware */
if (hal_can_init(&config->nominal_baudrate, config->frame_type,
config->enable_fd) != 0) {
return KERNEL_ERROR;
}
/* Configure filters */
for (uint8_t i = 0; i < config->filter_count; i++) {
if (config->filters[i].enable) {
hal_can_configure_filter(&config->filters[i]);
}
}
/* Enable CAN interrupts */
hal_can_enable_interrupts();
can_driver.initialized = true;
return KERNEL_OK;
}
/* Send CAN Message */
KernelStatus_t can_send_message(const CanMessage_t* message, uint32_t timeout_ms) {
if (!can_driver.initialized || message == NULL) {
return KERNEL_ERROR;
}
if (can_driver.bus_off) {
return KERNEL_ERROR;
}
/* Take TX semaphore with timeout */
if (semaphore_take(&can_driver.tx_semaphore, timeout_ms) != KERNEL_OK) {
can_driver.statistics.tx_overflow++;
return KERNEL_TIMEOUT;
}
/* Lock TX mutex */
if (mutex_lock(&can_driver.tx_mutex, timeout_ms) != KERNEL_OK) {
semaphore_give(&can_driver.tx_semaphore);
return KERNEL_TIMEOUT;
}
/* Send message via hardware */
uint32_t mailbox;
if (hal_can_send_message(message, &mailbox) != 0) {
mutex_unlock(&can_driver.tx_mutex);
semaphore_give(&can_driver.tx_semaphore);
can_driver.statistics.tx_errors++;
return KERNEL_ERROR;
}
/* Update statistics */
can_driver.statistics.tx_messages++;
/* Unlock TX mutex */
mutex_unlock(&can_driver.tx_mutex);
return KERNEL_OK;
}
/* Receive CAN Message */
KernelStatus_t can_receive_message(CanMessage_t* message, uint32_t timeout_ms) {
if (!can_driver.initialized || message == NULL) {
return KERNEL_ERROR;
}
/* Wait for message */
if (semaphore_take(&can_driver.rx_semaphore, timeout_ms) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Get message from FIFO */
critical_section_enter();
memcpy(message, &can_driver.rx_fifo[can_driver.rx_head], sizeof(CanMessage_t));
can_driver.rx_head = (can_driver.rx_head + 1) % CAN_MAX_RX_FIFO_DEPTH;
can_driver.rx_count--;
critical_section_exit();
can_driver.statistics.rx_messages++;
return KERNEL_OK;
}
/* CAN Interrupt Handler */
void can_process_interrupt(void) {
uint32_t interrupt_status = hal_can_get_interrupt_status();
/* Check for received messages */
if (interrupt_status & CAN_INTERRUPT_RX) {
CanMessage_t message;
while (hal_can_receive_message(&message) == 0) {
/* Add to RX FIFO */
critical_section_enter();
if (can_driver.rx_count < CAN_MAX_RX_FIFO_DEPTH) {
memcpy(&can_driver.rx_fifo[can_driver.rx_tail], &message,
sizeof(CanMessage_t));
can_driver.rx_tail = (can_driver.rx_tail + 1) % CAN_MAX_RX_FIFO_DEPTH;
can_driver.rx_count++;
/* Signal message available */
semaphore_give(&can_driver.rx_semaphore);
/* Call callback if registered */
if (can_driver.config.rx_callback != NULL) {
can_driver.config.rx_callback(&message);
}
} else {
can_driver.statistics.rx_overflow++;
}
critical_section_exit();
}
}
/* Check for transmit complete */
if (interrupt_status & CAN_INTERRUPT_TX) {
uint32_t mailbox = hal_can_get_tx_mailbox();
/* Release TX semaphore */
semaphore_give(&can_driver.tx_semaphore);
/* Call callback if registered */
if (can_driver.config.tx_callback != NULL) {
can_driver.config.tx_callback(mailbox, true);
}
}
/* Check for errors */
if (interrupt_status & CAN_INTERRUPT_ERROR) {
uint32_t error_code = hal_can_get_error_status();
can_driver.statistics.rx_errors++;
can_driver.statistics.tx_errors++;
/* Check for bus-off */
if (error_code & CAN_ERROR_BUS_OFF) {
can_driver.bus_off = true;
can_driver.statistics.bus_off_count++;
}
/* Call error callback */
if (can_driver.config.error_callback != NULL) {
can_driver.config.error_callback(error_code);
}
}
}
/* Recover from Bus-Off */
KernelStatus_t can_recover_bus_off(void) {
if (!can_driver.initialized) {
return KERNEL_ERROR;
}
/* Reset CAN controller */
hal_can_reset();
/* Reconfigure */
hal_can_init(&can_driver.config.nominal_baudrate,
can_driver.config.frame_type, can_driver.config.enable_fd);
/* Clear bus-off flag */
can_driver.bus_off = false;
return KERNEL_OK;
}
/* Get CAN Statistics */
KernelStatus_t can_get_statistics(CanStatistics_t* stats) {
if (stats == NULL) {
return KERNEL_ERROR;
}
memcpy(stats, &can_driver.statistics, sizeof(CanStatistics_t));
return KERNEL_OK;
}
+178
View File
@@ -0,0 +1,178 @@
/**
* @file gpio_driver.c
* @brief GPIO driver implementation
*/
#include "gpio_driver.h"
#include "isr.h"
#include <string.h>
/* GPIO Driver State */
typedef struct {
bool initialized;
GpioPinConfig_t pins[GPIO_MAX_PORTS][GPIO_MAX_PINS_PER_PORT];
GpioInterruptConfig_t interrupts[GPIO_MAX_INTERRUPTS];
uint8_t interrupt_count;
Mutex_t mutex;
} GpioDriverState_t;
static GpioDriverState_t gpio_driver;
/* Initialize GPIO Driver */
KernelStatus_t gpio_init(const GpioPinConfig_t* config) {
if (config == NULL) {
return KERNEL_INVALID_PARAMETER;
}
if (!gpio_driver.initialized) {
memset(&gpio_driver, 0, sizeof(GpioDriverState_t));
mutex_create(&gpio_driver.mutex, false);
gpio_driver.initialized = true;
}
/* Validate parameters */
if (config->port >= GPIO_MAX_PORTS || config->pin >= GPIO_MAX_PINS_PER_PORT) {
return KERNEL_INVALID_PARAMETER;
}
/* Store pin configuration */
gpio_driver.pins[config->port][config->pin] = *config;
/* Configure GPIO hardware */
hal_gpio_init(config->port, config->pin, config->mode);
/* Configure output type */
if (config->mode == GPIO_MODE_OUTPUT || config->mode == GPIO_MODE_ALTERNATE) {
hal_gpio_set_output_type(config->port, config->pin, config->output_type);
}
/* Configure pull */
hal_gpio_set_pull(config->port, config->pin, config->pull);
/* Configure speed */
hal_gpio_set_speed(config->port, config->pin, config->speed);
/* Configure alternate function */
if (config->mode == GPIO_MODE_ALTERNATE) {
hal_gpio_set_alternate_function(config->port, config->pin,
config->alternate_function);
}
return KERNEL_OK;
}
/* Set GPIO Mode */
KernelStatus_t gpio_set_mode(uint8_t port, uint8_t pin, GpioMode_t mode) {
if (port >= GPIO_MAX_PORTS || pin >= GPIO_MAX_PINS_PER_PORT) {
return KERNEL_INVALID_PARAMETER;
}
gpio_driver.pins[port][pin].mode = mode;
hal_gpio_init(port, pin, mode);
return KERNEL_OK;
}
/* Write GPIO Pin */
KernelStatus_t gpio_write(uint8_t port, uint8_t pin, bool value) {
if (port >= GPIO_MAX_PORTS || pin >= GPIO_MAX_PINS_PER_PORT) {
return KERNEL_INVALID_PARAMETER;
}
if (gpio_driver.pins[port][pin].mode != GPIO_MODE_OUTPUT) {
return KERNEL_ERROR;
}
hal_gpio_write(port, pin, value);
return KERNEL_OK;
}
/* Write GPIO Port */
KernelStatus_t gpio_write_port(uint8_t port, uint16_t value) {
if (port >= GPIO_MAX_PORTS) {
return KERNEL_INVALID_PARAMETER;
}
hal_gpio_write_port(port, value);
return KERNEL_OK;
}
/* Read GPIO Pin */
bool gpio_read(uint8_t port, uint8_t pin) {
if (port >= GPIO_MAX_PORTS || pin >= GPIO_MAX_PINS_PER_PORT) {
return false;
}
return hal_gpio_read(port, pin);
}
/* Read GPIO Port */
uint16_t gpio_read_port(uint8_t port) {
if (port >= GPIO_MAX_PORTS) {
return 0;
}
return hal_gpio_read_port(port);
}
/* Toggle GPIO Pin */
KernelStatus_t gpio_toggle(uint8_t port, uint8_t pin) {
if (port >= GPIO_MAX_PORTS || pin >= GPIO_MAX_PINS_PER_PORT) {
return KERNEL_INVALID_PARAMETER;
}
hal_gpio_toggle(port, pin);
return KERNEL_OK;
}
/* Configure GPIO Interrupt */
KernelStatus_t gpio_configure_interrupt(const GpioInterruptConfig_t* config) {
if (config == NULL || config->callback == NULL) {
return KERNEL_INVALID_PARAMETER;
}
if (config->port >= GPIO_MAX_PORTS || config->pin >= GPIO_MAX_PINS_PER_PORT) {
return KERNEL_INVALID_PARAMETER;
}
if (gpio_driver.interrupt_count >= GPIO_MAX_INTERRUPTS) {
return KERNEL_OUT_OF_MEMORY;
}
/* Store interrupt configuration */
gpio_driver.interrupts[gpio_driver.interrupt_count] = *config;
gpio_driver.interrupt_count++;
/* Configure hardware interrupt */
hal_gpio_configure_interrupt(config->port, config->pin, config->trigger);
return KERNEL_OK;
}
/* GPIO Interrupt Handler */
void gpio_process_interrupt(uint8_t port) {
if (port >= GPIO_MAX_PORTS) {
return;
}
/* Get interrupt status */
uint16_t interrupt_status = hal_gpio_get_interrupt_status(port);
/* Process each interrupt */
for (uint8_t pin = 0; pin < GPIO_MAX_PINS_PER_PORT; pin++) {
if (interrupt_status & (1 << pin)) {
/* Find matching interrupt configuration */
for (uint8_t i = 0; i < gpio_driver.interrupt_count; i++) {
if (gpio_driver.interrupts[i].port == port &&
gpio_driver.interrupts[i].pin == pin) {
/* Call callback */
gpio_driver.interrupts[i].callback(port, pin);
break;
}
}
/* Clear interrupt flag */
hal_gpio_clear_interrupt(port, pin);
}
}
}
+301
View File
@@ -0,0 +1,301 @@
/**
* @file i2c_driver.c
* @brief I2C driver implementation
*/
#include "i2c_driver.h"
#include "isr.h"
#include <string.h>
/* I2C Driver State */
typedef struct {
bool initialized;
I2cConfig_t config;
I2cStatistics_t statistics;
I2cMessage_t current_message;
uint16_t transfer_index;
bool transfer_active;
Semaphore_t transfer_semaphore;
Mutex_t transfer_mutex;
void* user_data;
} I2cDriverState_t;
static I2cDriverState_t i2c_drivers[I2C_MAX_INSTANCES];
/* Initialize I2C Driver */
KernelStatus_t i2c_init(uint8_t instance, I2cConfig_t* config) {
if (instance >= I2C_MAX_INSTANCES || config == NULL) {
return KERNEL_INVALID_PARAMETER;
}
I2cDriverState_t* driver = &i2c_drivers[instance];
if (driver->initialized) {
return KERNEL_ERROR;
}
/* Copy configuration */
memcpy(&driver->config, config, sizeof(I2cConfig_t));
/* Initialize state */
memset(&driver->statistics, 0, sizeof(I2cStatistics_t));
driver->transfer_index = 0;
driver->transfer_active = false;
/* Create synchronization primitives */
semaphore_create(&driver->transfer_semaphore, SEMAPHORE_BINARY, 1, 1);
mutex_create(&driver->transfer_mutex, false);
/* Initialize I2C hardware */
if (hal_i2c_init(instance, config) != 0) {
return KERNEL_ERROR;
}
/* Enable interrupts */
hal_i2c_enable_interrupts(instance);
driver->initialized = true;
return KERNEL_OK;
}
/* I2C Transfer */
KernelStatus_t i2c_transfer(uint8_t instance, const I2cMessage_t* message,
uint32_t timeout_ms) {
if (instance >= I2C_MAX_INSTANCES || message == NULL ||
message->data == NULL || message->length == 0) {
return KERNEL_INVALID_PARAMETER;
}
I2cDriverState_t* driver = &i2c_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
if (driver->transfer_active) {
return KERNEL_RESOURCE_BUSY;
}
/* Take transfer semaphore */
if (semaphore_take(&driver->transfer_semaphore, timeout_ms) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Lock transfer mutex */
if (mutex_lock(&driver->transfer_mutex, timeout_ms) != KERNEL_OK) {
semaphore_give(&driver->transfer_semaphore);
return KERNEL_TIMEOUT;
}
/* Set up transfer */
memcpy(&driver->current_message, message, sizeof(I2cMessage_t));
driver->transfer_index = 0;
driver->transfer_active = true;
/* Start transfer */
if (message->direction == I2C_DIRECTION_WRITE) {
hal_i2c_start_write(instance, message->slave_address);
} else {
hal_i2c_start_read(instance, message->slave_address);
}
/* Wait for completion */
if (timeout_ms > 0) {
TickType_t start_tick = kernel_get_tick_count();
while (driver->transfer_active) {
if ((kernel_get_tick_count() - start_tick) > timeout_ms) {
/* Timeout - abort transfer */
hal_i2c_abort_transfer(instance);
driver->transfer_active = false;
mutex_unlock(&driver->transfer_mutex);
semaphore_give(&driver->transfer_semaphore);
driver->statistics.timeout_errors++;
return KERNEL_TIMEOUT;
}
kernel_delay(1);
}
}
/* Update statistics */
driver->statistics.transfers_completed++;
driver->statistics.bytes_transferred += message->length;
/* Unlock */
mutex_unlock(&driver->transfer_mutex);
semaphore_give(&driver->transfer_semaphore);
return KERNEL_OK;
}
/* I2C Write */
KernelStatus_t i2c_write(uint8_t instance, uint16_t slave_address,
const uint8_t* data, uint16_t length, uint32_t timeout_ms) {
I2cMessage_t message = {
.slave_address = slave_address,
.direction = I2C_DIRECTION_WRITE,
.data = (uint8_t*)data,
.length = length,
.generate_stop = true,
.generate_restart = false
};
return i2c_transfer(instance, &message, timeout_ms);
}
/* I2C Read */
KernelStatus_t i2c_read(uint8_t instance, uint16_t slave_address,
uint8_t* data, uint16_t length, uint32_t timeout_ms) {
I2cMessage_t message = {
.slave_address = slave_address,
.direction = I2C_DIRECTION_READ,
.data = data,
.length = length,
.generate_stop = true,
.generate_restart = false
};
return i2c_transfer(instance, &message, timeout_ms);
}
/* I2C Write/Read */
KernelStatus_t i2c_write_read(uint8_t instance, uint16_t slave_address,
const uint8_t* tx_data, uint16_t tx_length,
uint8_t* rx_data, uint16_t rx_length,
uint32_t timeout_ms) {
/* First write */
I2cMessage_t write_message = {
.slave_address = slave_address,
.direction = I2C_DIRECTION_WRITE,
.data = (uint8_t*)tx_data,
.length = tx_length,
.generate_stop = false,
.generate_restart = true
};
KernelStatus_t status = i2c_transfer(instance, &write_message, timeout_ms);
if (status != KERNEL_OK) {
return status;
}
/* Then read */
I2cMessage_t read_message = {
.slave_address = slave_address,
.direction = I2C_DIRECTION_READ,
.data = rx_data,
.length = rx_length,
.generate_stop = true,
.generate_restart = false
};
return i2c_transfer(instance, &read_message, timeout_ms);
}
/* Check if Device is Ready */
bool i2c_is_device_ready(uint8_t instance, uint16_t slave_address) {
if (instance >= I2C_MAX_INSTANCES) {
return false;
}
I2cDriverState_t* driver = &i2c_drivers[instance];
if (!driver->initialized) {
return false;
}
return hal_i2c_check_device(instance, slave_address);
}
/* I2C Interrupt Handler */
void i2c_process_interrupt(uint8_t instance) {
if (instance >= I2C_MAX_INSTANCES) {
return;
}
I2cDriverState_t* driver = &i2c_drivers[instance];
if (!driver->initialized || !driver->transfer_active) {
return;
}
uint32_t interrupt_status = hal_i2c_get_interrupt_status(instance);
/* Handle address sent */
if (interrupt_status & I2C_INTERRUPT_ADDRESS_SENT) {
if (driver->current_message.direction == I2C_DIRECTION_READ) {
hal_i2c_prepare_receive(instance);
}
}
/* Handle data transfer */
if (interrupt_status & I2C_INTERRUPT_DATA) {
if (driver->transfer_index < driver->current_message.length) {
if (driver->current_message.direction == I2C_DIRECTION_WRITE) {
/* Transmit next byte */
uint8_t byte = driver->current_message.data[driver->transfer_index];
hal_i2c_transmit_byte(instance, byte);
} else {
/* Receive next byte */
driver->current_message.data[driver->transfer_index] =
hal_i2c_receive_byte(instance);
}
driver->transfer_index++;
/* Check if last byte */
if (driver->transfer_index == driver->current_message.length) {
if (driver->current_message.generate_stop) {
hal_i2c_generate_stop(instance);
}
}
}
}
/* Handle NACK */
if (interrupt_status & I2C_INTERRUPT_NACK) {
driver->transfer_active = false;
driver->statistics.nack_errors++;
if (driver->config.transfer_complete_callback != NULL) {
driver->config.transfer_complete_callback(I2C_TRANSFER_NACK,
driver->user_data);
}
semaphore_give(&driver->transfer_semaphore);
}
/* Handle transfer complete */
if (interrupt_status & I2C_INTERRUPT_COMPLETE) {
driver->transfer_active = false;
if (driver->config.transfer_complete_callback != NULL) {
driver->config.transfer_complete_callback(I2C_TRANSFER_COMPLETE,
driver->user_data);
}
semaphore_give(&driver->transfer_semaphore);
}
/* Handle errors */
if (interrupt_status & I2C_INTERRUPT_ERROR) {
driver->transfer_active = false;
driver->statistics.transfers_failed++;
uint32_t error = hal_i2c_get_error(instance);
if (error & I2C_ERROR_ARBITRATION_LOST) {
driver->statistics.arbitration_lost++;
}
if (error & I2C_ERROR_BUS) {
driver->statistics.bus_errors++;
}
if (driver->config.transfer_complete_callback != NULL) {
driver->config.transfer_complete_callback(I2C_TRANSFER_ERROR,
driver->user_data);
}
semaphore_give(&driver->transfer_semaphore);
}
}
+328
View File
@@ -0,0 +1,328 @@
/**
* @file pwm_driver.c
* @brief PWM driver implementation
*/
#include "pwm_driver.h"
#include "isr.h"
#include <string.h>
/* PWM Driver State */
typedef struct {
bool initialized;
PwmConfig_t config;
PwmStatistics_t statistics;
uint32_t current_duty_cycles[PWM_MAX_CHANNELS];
bool channel_enabled[PWM_MAX_CHANNELS];
uint32_t fault_flags;
Mutex_t mutex;
} PwmDriverState_t;
static PwmDriverState_t pwm_drivers[PWM_MAX_INSTANCES];
/* Initialize PWM Driver */
KernelStatus_t pwm_init(uint8_t instance, PwmConfig_t* config) {
if (instance >= PWM_MAX_INSTANCES || config == NULL) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (driver->initialized) {
return KERNEL_ERROR;
}
/* Copy configuration */
memcpy(&driver->config, config, sizeof(PwmConfig_t));
/* Initialize state */
memset(&driver->statistics, 0, sizeof(PwmStatistics_t));
driver->fault_flags = 0;
/* Initialize channel states */
for (uint8_t i = 0; i < PWM_MAX_CHANNELS; i++) {
driver->current_duty_cycles[i] = 0;
driver->channel_enabled[i] = false;
}
/* Create mutex */
mutex_create(&driver->mutex, false);
/* Initialize PWM hardware */
if (hal_pwm_init(instance, config) != 0) {
return KERNEL_ERROR;
}
/* Configure channels */
for (uint8_t i = 0; i < config->channel_count; i++) {
driver->current_duty_cycles[config->channels[i].channel] =
config->channels[i].duty_cycle;
driver->channel_enabled[config->channels[i].channel] = true;
hal_pwm_configure_channel(instance, &config->channels[i]);
}
/* Configure fault protection */
if (config->enable_fault_protection) {
hal_pwm_configure_fault(instance, config->fault_action);
}
/* Enable interrupts */
hal_pwm_enable_interrupts(instance);
driver->initialized = true;
return KERNEL_OK;
}
/* Start PWM */
KernelStatus_t pwm_start(uint8_t instance) {
if (instance >= PWM_MAX_INSTANCES) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
hal_pwm_start(instance);
return KERNEL_OK;
}
/* Stop PWM */
KernelStatus_t pwm_stop(uint8_t instance) {
if (instance >= PWM_MAX_INSTANCES) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
hal_pwm_stop(instance);
return KERNEL_OK;
}
/* Set PWM Duty Cycle */
KernelStatus_t pwm_set_duty_cycle(uint8_t instance, uint8_t channel,
uint32_t duty_cycle) {
if (instance >= PWM_MAX_INSTANCES || channel >= PWM_MAX_CHANNELS) {
return KERNEL_INVALID_PARAMETER;
}
if (duty_cycle > PWM_MAX_DUTY_CYCLE) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
/* Lock mutex */
if (mutex_lock(&driver->mutex, 100) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Update duty cycle */
driver->current_duty_cycles[channel] = duty_cycle;
driver->statistics.duty_cycle_updates++;
/* Update hardware */
hal_pwm_set_duty_cycle(instance, channel, duty_cycle);
/* Unlock mutex */
mutex_unlock(&driver->mutex);
return KERNEL_OK;
}
/* Set PWM Frequency */
KernelStatus_t pwm_set_frequency(uint8_t instance, uint32_t frequency_hz) {
if (instance >= PWM_MAX_INSTANCES || frequency_hz == 0) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
/* Lock mutex */
if (mutex_lock(&driver->mutex, 100) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Update frequency */
driver->config.frequency_hz = frequency_hz;
/* Update hardware */
hal_pwm_set_frequency(instance, frequency_hz);
/* Unlock mutex */
mutex_unlock(&driver->mutex);
return KERNEL_OK;
}
/* Set PWM Dead Time */
KernelStatus_t pwm_set_dead_time(uint8_t instance, uint8_t channel,
const PwmDeadTime_t* dead_time) {
if (instance >= PWM_MAX_INSTANCES || channel >= PWM_MAX_CHANNELS ||
dead_time == NULL) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
/* Lock mutex */
if (mutex_lock(&driver->mutex, 100) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Update dead time */
driver->config.channels[channel].dead_time = *dead_time;
/* Update hardware */
hal_pwm_set_dead_time(instance, channel, dead_time);
/* Unlock mutex */
mutex_unlock(&driver->mutex);
return KERNEL_OK;
}
/* Enable PWM Channel */
KernelStatus_t pwm_enable_channel(uint8_t instance, uint8_t channel) {
if (instance >= PWM_MAX_INSTANCES || channel >= PWM_MAX_CHANNELS) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
driver->channel_enabled[channel] = true;
hal_pwm_enable_channel(instance, channel);
return KERNEL_OK;
}
/* Disable PWM Channel */
KernelStatus_t pwm_disable_channel(uint8_t instance, uint8_t channel) {
if (instance >= PWM_MAX_INSTANCES || channel >= PWM_MAX_CHANNELS) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
driver->channel_enabled[channel] = false;
hal_pwm_disable_channel(instance, channel);
return KERNEL_OK;
}
/* Clear PWM Fault */
KernelStatus_t pwm_clear_fault(uint8_t instance) {
if (instance >= PWM_MAX_INSTANCES) {
return KERNEL_INVALID_PARAMETER;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
driver->fault_flags = 0;
hal_pwm_clear_fault(instance);
return KERNEL_OK;
}
/* PWM Interrupt Handler */
void pwm_process_interrupt(uint8_t instance) {
if (instance >= PWM_MAX_INSTANCES) {
return;
}
PwmDriverState_t* driver = &pwm_drivers[instance];
if (!driver->initialized) {
return;
}
uint32_t interrupt_status = hal_pwm_get_interrupt_status(instance);
/* Handle period elapsed */
if (interrupt_status & PWM_INTERRUPT_PERIOD_ELAPSED) {
driver->statistics.period_elapsed_count++;
/* Call callback */
if (driver->config.period_elapsed_callback != NULL) {
driver->config.period_elapsed_callback(instance);
}
}
/* Handle fault */
if (interrupt_status & PWM_INTERRUPT_FAULT) {
driver->statistics.fault_events++;
driver->fault_flags = hal_pwm_get_fault_flags(instance);
/* Apply fault action */
hal_pwm_apply_fault_action(instance, driver->config.fault_action);
/* Call callback */
if (driver->config.fault_callback != NULL) {
driver->config.fault_callback(instance, driver->fault_flags);
}
}
/* Clear interrupt flags */
hal_pwm_clear_interrupts(instance, interrupt_status);
}
/* Get PWM Statistics */
KernelStatus_t pwm_get_statistics(uint8_t instance, PwmStatistics_t* stats) {
if (instance >= PWM_MAX_INSTANCES || stats == NULL) {
return KERNEL_INVALID_PARAMETER;
}
memcpy(stats, &pwm_drivers[instance].statistics, sizeof(PwmStatistics_t));
return KERNEL_OK;
}
/* Get PWM Duty Cycle */
uint32_t pwm_get_duty_cycle(uint8_t instance, uint8_t channel) {
if (instance >= PWM_MAX_INSTANCES || channel >= PWM_MAX_CHANNELS) {
return 0;
}
return pwm_drivers[instance].current_duty_cycles[channel];
}
/* Get PWM Frequency */
uint32_t pwm_get_frequency(uint8_t instance) {
if (instance >= PWM_MAX_INSTANCES) {
return 0;
}
return pwm_drivers[instance].config.frequency_hz;
}
+320
View File
@@ -0,0 +1,320 @@
/**
* @file spi_driver.c
* @brief SPI driver implementation
*/
#include "spi_driver.h"
#include "isr.h"
#include <string.h>
/* SPI Driver State */
typedef struct {
bool initialized;
SpiConfig_t config;
SpiStatistics_t statistics;
uint8_t tx_buffer[SPI_MAX_BUFFER_SIZE];
uint8_t rx_buffer[SPI_MAX_BUFFER_SIZE];
uint16_t transfer_length;
uint16_t transfer_index;
bool transfer_active;
bool use_dma;
Semaphore_t transfer_semaphore;
Mutex_t transfer_mutex;
void* user_data;
} SpiDriverState_t;
static SpiDriverState_t spi_drivers[SPI_MAX_INSTANCES];
/* Initialize SPI Driver */
KernelStatus_t spi_init(uint8_t instance, SpiConfig_t* config) {
if (instance >= SPI_MAX_INSTANCES || config == NULL) {
return KERNEL_INVALID_PARAMETER;
}
SpiDriverState_t* driver = &spi_drivers[instance];
if (driver->initialized) {
return KERNEL_ERROR;
}
/* Copy configuration */
memcpy(&driver->config, config, sizeof(SpiConfig_t));
/* Initialize state */
memset(&driver->statistics, 0, sizeof(SpiStatistics_t));
driver->transfer_length = 0;
driver->transfer_index = 0;
driver->transfer_active = false;
driver->use_dma = config->use_dma;
/* Create synchronization primitives */
semaphore_create(&driver->transfer_semaphore, SEMAPHORE_BINARY, 1, 1);
mutex_create(&driver->transfer_mutex, false);
/* Initialize SPI hardware */
if (hal_spi_init(instance, config) != 0) {
return KERNEL_ERROR;
}
/* Enable interrupts if not using DMA */
if (!driver->use_dma) {
hal_spi_enable_interrupts(instance);
}
driver->initialized = true;
return KERNEL_OK;
}
/* SPI Transfer */
KernelStatus_t spi_transfer(uint8_t instance, const SpiTransaction_t* transaction,
uint32_t timeout_ms) {
if (instance >= SPI_MAX_INSTANCES || transaction == NULL ||
transaction->length == 0) {
return KERNEL_INVALID_PARAMETER;
}
SpiDriverState_t* driver = &spi_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
/* Check if transfer is already active */
if (driver->transfer_active) {
return KERNEL_RESOURCE_BUSY;
}
/* Take transfer semaphore */
if (semaphore_take(&driver->transfer_semaphore, timeout_ms) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Lock transfer mutex */
if (mutex_lock(&driver->transfer_mutex, timeout_ms) != KERNEL_OK) {
semaphore_give(&driver->transfer_semaphore);
return KERNEL_TIMEOUT;
}
/* Set up transfer */
driver->transfer_length = transaction->length;
driver->transfer_index = 0;
driver->transfer_active = true;
driver->user_data = transaction->user_data;
/* Copy TX data if provided */
if (transaction->tx_data != NULL) {
memcpy(driver->tx_buffer, transaction->tx_data, transaction->length);
} else {
memset(driver->tx_buffer, 0xFF, transaction->length); /* Dummy data */
}
/* Clear RX buffer */
memset(driver->rx_buffer, 0, transaction->length);
/* Select chip if hardware CS is not used */
if (!driver->config.enable_hardware_cs) {
spi_set_chip_select(instance, true);
}
/* Start transfer */
if (driver->use_dma) {
hal_spi_start_dma_transfer(instance, driver->tx_buffer, driver->rx_buffer,
transaction->length);
} else {
hal_spi_start_transfer(instance);
}
/* Wait for completion */
if (timeout_ms > 0) {
TickType_t start_tick = kernel_get_tick_count();
while (driver->transfer_active) {
if ((kernel_get_tick_count() - start_tick) > timeout_ms) {
/* Timeout - abort transfer */
hal_spi_abort_transfer(instance);
driver->transfer_active = false;
if (!driver->config.enable_hardware_cs) {
spi_set_chip_select(instance, false);
}
mutex_unlock(&driver->transfer_mutex);
semaphore_give(&driver->transfer_semaphore);
driver->statistics.timeout_errors++;
return KERNEL_TIMEOUT;
}
kernel_delay(1);
}
}
/* Copy RX data if requested */
if (transaction->rx_data != NULL) {
memcpy(transaction->rx_data, driver->rx_buffer, transaction->length);
}
/* Deselect chip */
if (!driver->config.enable_hardware_cs) {
spi_set_chip_select(instance, false);
}
/* Update statistics */
driver->statistics.transfers_completed++;
driver->statistics.bytes_transferred += transaction->length;
/* Unlock */
mutex_unlock(&driver->transfer_mutex);
semaphore_give(&driver->transfer_semaphore);
return KERNEL_OK;
}
/* SPI Transfer Asynchronously */
KernelStatus_t spi_transfer_async(uint8_t instance, const SpiTransaction_t* transaction) {
if (instance >= SPI_MAX_INSTANCES || transaction == NULL ||
transaction->length == 0) {
return KERNEL_INVALID_PARAMETER;
}
SpiDriverState_t* driver = &spi_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
if (driver->transfer_active) {
return KERNEL_RESOURCE_BUSY;
}
/* Set up transfer */
driver->transfer_length = transaction->length;
driver->transfer_index = 0;
driver->transfer_active = true;
driver->user_data = transaction->user_data;
/* Copy TX data */
if (transaction->tx_data != NULL) {
memcpy(driver->tx_buffer, transaction->tx_data, transaction->length);
} else {
memset(driver->tx_buffer, 0xFF, transaction->length);
}
/* Select chip */
if (!driver->config.enable_hardware_cs) {
spi_set_chip_select(instance, true);
}
/* Start transfer */
if (driver->use_dma) {
hal_spi_start_dma_transfer(instance, driver->tx_buffer, driver->rx_buffer,
transaction->length);
} else {
hal_spi_start_transfer(instance);
}
return KERNEL_OK;
}
/* SPI Read */
KernelStatus_t spi_read(uint8_t instance, uint8_t* data, uint16_t length,
uint32_t timeout_ms) {
SpiTransaction_t transaction = {
.tx_data = NULL,
.rx_data = data,
.length = length,
.keep_cs_active = false,
.user_data = NULL
};
return spi_transfer(instance, &transaction, timeout_ms);
}
/* SPI Write */
KernelStatus_t spi_write(uint8_t instance, const uint8_t* data, uint16_t length,
uint32_t timeout_ms) {
SpiTransaction_t transaction = {
.tx_data = data,
.rx_data = NULL,
.length = length,
.keep_cs_active = false,
.user_data = NULL
};
return spi_transfer(instance, &transaction, timeout_ms);
}
/* SPI Read/Write */
KernelStatus_t spi_read_write(uint8_t instance, const uint8_t* tx_data,
uint8_t* rx_data, uint16_t length, uint32_t timeout_ms) {
SpiTransaction_t transaction = {
.tx_data = tx_data,
.rx_data = rx_data,
.length = length,
.keep_cs_active = false,
.user_data = NULL
};
return spi_transfer(instance, &transaction, timeout_ms);
}
/* SPI Interrupt Handler */
void spi_process_interrupt(uint8_t instance) {
if (instance >= SPI_MAX_INSTANCES) {
return;
}
SpiDriverState_t* driver = &spi_drivers[instance];
if (!driver->initialized || !driver->transfer_active) {
return;
}
/* Check if more data to transfer */
if (driver->transfer_index < driver->transfer_length) {
/* Transmit next byte */
uint8_t tx_byte = driver->tx_buffer[driver->transfer_index];
uint8_t rx_byte = hal_spi_transfer_byte(instance, tx_byte);
/* Store received byte */
if (driver->transfer_index < SPI_MAX_BUFFER_SIZE) {
driver->rx_buffer[driver->transfer_index] = rx_byte;
}
driver->transfer_index++;
} else {
/* Transfer complete */
driver->transfer_active = false;
/* Deselect chip */
if (!driver->config.enable_hardware_cs) {
spi_set_chip_select(instance, false);
}
/* Update statistics */
driver->statistics.transfers_completed++;
driver->statistics.bytes_transferred += driver->transfer_length;
/* Call callback */
if (driver->config.transfer_complete_callback != NULL) {
driver->config.transfer_complete_callback(SPI_TRANSFER_COMPLETE,
driver->user_data);
}
/* Signal completion */
semaphore_give(&driver->transfer_semaphore);
}
}
/* Set Chip Select */
void spi_set_chip_select(uint8_t instance, bool active) {
if (instance >= SPI_MAX_INSTANCES) {
return;
}
SpiDriverState_t* driver = &spi_drivers[instance];
bool cs_level = active ?
(driver->config.cs_polarity == SPI_CS_ACTIVE_LOW ? false : true) :
(driver->config.cs_polarity == SPI_CS_ACTIVE_LOW ? true : false);
gpio_write(driver->config.cs_port, driver->config.cs_pin, cs_level);
}
+325
View File
@@ -0,0 +1,325 @@
/**
* @file uart_driver.c
* @brief UART driver implementation
*/
#include "uart_driver.h"
#include "isr.h"
#include <string.h>
/* UART Driver State */
typedef struct {
bool initialized;
UartConfig_t config;
UartStatistics_t statistics;
uint8_t tx_buffer[UART_MAX_BUFFER_SIZE];
uint8_t rx_buffer[UART_MAX_BUFFER_SIZE];
uint16_t tx_head;
uint16_t tx_tail;
uint16_t rx_head;
uint16_t rx_tail;
uint16_t tx_count;
uint16_t rx_count;
Semaphore_t tx_semaphore;
Semaphore_t rx_semaphore;
Mutex_t tx_mutex;
Mutex_t rx_mutex;
} UartDriverState_t;
static UartDriverState_t uart_drivers[UART_MAX_INSTANCES];
/* Initialize UART Driver */
KernelStatus_t uart_init(uint8_t instance, UartConfig_t* config) {
if (instance >= UART_MAX_INSTANCES || config == NULL) {
return KERNEL_INVALID_PARAMETER;
}
UartDriverState_t* driver = &uart_drivers[instance];
if (driver->initialized) {
return KERNEL_ERROR;
}
/* Copy configuration */
memcpy(&driver->config, config, sizeof(UartConfig_t));
/* Initialize state */
memset(&driver->statistics, 0, sizeof(UartStatistics_t));
driver->tx_head = 0;
driver->tx_tail = 0;
driver->rx_head = 0;
driver->rx_tail = 0;
driver->tx_count = 0;
driver->rx_count = 0;
/* Create synchronization primitives */
semaphore_create(&driver->tx_semaphore, SEMAPHORE_COUNTING,
UART_MAX_BUFFER_SIZE, UART_MAX_BUFFER_SIZE);
semaphore_create(&driver->rx_semaphore, SEMAPHORE_COUNTING, 0,
UART_MAX_BUFFER_SIZE);
mutex_create(&driver->tx_mutex, false);
mutex_create(&driver->rx_mutex, false);
/* Initialize UART hardware */
if (hal_uart_init(instance, config) != 0) {
return KERNEL_ERROR;
}
/* Enable interrupts */
hal_uart_enable_interrupts(instance, true, true);
driver->initialized = true;
return KERNEL_OK;
}
/* Send Data via UART */
KernelStatus_t uart_send(uint8_t instance, const uint8_t* data, uint16_t length,
uint32_t timeout_ms) {
if (instance >= UART_MAX_INSTANCES || data == NULL || length == 0) {
return KERNEL_INVALID_PARAMETER;
}
UartDriverState_t* driver = &uart_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
/* Lock TX mutex */
if (mutex_lock(&driver->tx_mutex, timeout_ms) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Check if async transfer is in progress */
if (driver->tx_count > 0) {
mutex_unlock(&driver->tx_mutex);
return KERNEL_RESOURCE_BUSY;
}
/* Copy data to TX buffer */
uint16_t copy_length = (length < UART_MAX_BUFFER_SIZE) ? length : UART_MAX_BUFFER_SIZE;
critical_section_enter();
memcpy(driver->tx_buffer, data, copy_length);
driver->tx_head = 0;
driver->tx_tail = copy_length;
driver->tx_count = copy_length;
critical_section_exit();
/* Start transmission */
hal_uart_start_tx(instance);
/* Wait for completion if synchronous */
if (timeout_ms > 0) {
TickType_t start_tick = kernel_get_tick_count();
while (driver->tx_count > 0) {
if ((kernel_get_tick_count() - start_tick) > timeout_ms) {
mutex_unlock(&driver->tx_mutex);
driver->statistics.tx_errors++;
return KERNEL_TIMEOUT;
}
kernel_delay(1);
}
}
/* Update statistics */
driver->statistics.tx_bytes += copy_length;
/* Unlock TX mutex */
mutex_unlock(&driver->tx_mutex);
return KERNEL_OK;
}
/* Receive Data via UART */
KernelStatus_t uart_receive(uint8_t instance, uint8_t* data, uint16_t length,
uint32_t timeout_ms) {
if (instance >= UART_MAX_INSTANCES || data == NULL || length == 0) {
return KERNEL_INVALID_PARAMETER;
}
UartDriverState_t* driver = &uart_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
/* Wait for data */
if (semaphore_take(&driver->rx_semaphore, timeout_ms) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Lock RX mutex */
if (mutex_lock(&driver->rx_mutex, timeout_ms) != KERNEL_OK) {
return KERNEL_TIMEOUT;
}
/* Copy data from RX buffer */
critical_section_enter();
uint16_t copy_length = 0;
while (copy_length < length && driver->rx_count > 0) {
data[copy_length] = driver->rx_buffer[driver->rx_head];
driver->rx_head = (driver->rx_head + 1) % UART_MAX_BUFFER_SIZE;
driver->rx_count--;
copy_length++;
}
critical_section_exit();
/* Update statistics */
driver->statistics.rx_bytes += copy_length;
/* Unlock RX mutex */
mutex_unlock(&driver->rx_mutex);
return (copy_length == length) ? KERNEL_OK : KERNEL_TIMEOUT;
}
/* Send Data Asynchronously */
KernelStatus_t uart_send_async(uint8_t instance, const uint8_t* data, uint16_t length) {
if (instance >= UART_MAX_INSTANCES || data == NULL || length == 0) {
return KERNEL_INVALID_PARAMETER;
}
UartDriverState_t* driver = &uart_drivers[instance];
if (!driver->initialized) {
return KERNEL_ERROR;
}
if (driver->tx_count > 0) {
return KERNEL_RESOURCE_BUSY;
}
/* Copy data to TX buffer */
uint16_t copy_length = (length < UART_MAX_BUFFER_SIZE) ? length : UART_MAX_BUFFER_SIZE;
critical_section_enter();
memcpy(driver->tx_buffer, data, copy_length);
driver->tx_head = 0;
driver->tx_tail = copy_length;
driver->tx_count = copy_length;
critical_section_exit();
/* Start transmission */
hal_uart_start_tx(instance);
return KERNEL_OK;
}
/* UART Interrupt Handler */
void uart_process_interrupt(uint8_t instance) {
if (instance >= UART_MAX_INSTANCES) {
return;
}
UartDriverState_t* driver = &uart_drivers[instance];
if (!driver->initialized) {
return;
}
uint32_t interrupt_status = hal_uart_get_interrupt_status(instance);
/* Handle TX complete */
if (interrupt_status & UART_INTERRUPT_TX_COMPLETE) {
if (driver->tx_count > 0) {
/* Get next byte to transmit */
uint8_t byte = driver->tx_buffer[driver->tx_head];
driver->tx_head = (driver->tx_head + 1) % UART_MAX_BUFFER_SIZE;
driver->tx_count--;
/* Transmit byte */
hal_uart_transmit_byte(instance, byte);
if (driver->tx_count == 0) {
/* All data transmitted */
if (driver->config.tx_callback != NULL) {
driver->config.tx_callback();
}
hal_uart_disable_tx_interrupt(instance);
}
}
}
/* Handle RX ready */
if (interrupt_status & UART_INTERRUPT_RX_READY) {
while (hal_uart_is_rx_ready(instance)) {
uint8_t byte = hal_uart_receive_byte(instance);
/* Add to RX buffer */
critical_section_enter();
if (driver->rx_count < UART_MAX_BUFFER_SIZE) {
driver->rx_buffer[driver->rx_tail] = byte;
driver->rx_tail = (driver->rx_tail + 1) % UART_MAX_BUFFER_SIZE;
driver->rx_count++;
/* Signal data available */
semaphore_give(&driver->rx_semaphore);
/* Call callback if registered */
if (driver->config.rx_callback != NULL) {
driver->config.rx_callback(&byte, 1);
}
} else {
driver->statistics.rx_errors++;
driver->statistics.overrun_errors++;
}
critical_section_exit();
}
}
/* Handle errors */
if (interrupt_status & UART_INTERRUPT_ERROR) {
uint32_t error = hal_uart_get_error_status(instance);
if (error & UART_ERROR_PARITY) {
driver->statistics.parity_errors++;
}
if (error & UART_ERROR_FRAMING) {
driver->statistics.framing_errors++;
}
if (error & UART_ERROR_OVERRUN) {
driver->statistics.overrun_errors++;
}
if (driver->config.error_callback != NULL) {
driver->config.error_callback(error);
}
/* Clear error flags */
hal_uart_clear_errors(instance);
}
}
/* Get UART Statistics */
KernelStatus_t uart_get_statistics(uint8_t instance, UartStatistics_t* stats) {
if (instance >= UART_MAX_INSTANCES || stats == NULL) {
return KERNEL_INVALID_PARAMETER;
}
memcpy(stats, &uart_drivers[instance].statistics, sizeof(UartStatistics_t));
return KERNEL_OK;
}
/* Get RX Count */
uint16_t uart_get_rx_count(uint8_t instance) {
if (instance >= UART_MAX_INSTANCES) {
return 0;
}
return uart_drivers[instance].rx_count;
}
/* Get TX Count */
uint16_t uart_get_tx_count(uint8_t instance) {
if (instance >= UART_MAX_INSTANCES) {
return 0;
}
return uart_drivers[instance].tx_count;
}