ca13734bf0
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.
225 lines
5.8 KiB
C
225 lines
5.8 KiB
C
/**
|
|
* @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;
|
|
}
|
|
}
|