From 06989267fe153e228c56faf8c448eb8cf69eb917 Mon Sep 17 00:00:00 2001 From: Michele Balistreri Date: Fri, 24 Mar 2023 18:27:38 +0100 Subject: [PATCH] start screen driver implementation --- app/hal.h | 14 + app/screen/screen.c | 1 + app/screen/screen.h | 18 + app/screen/st7789.c | 61 + app/screen/st7789.h | 85 ++ app/tasks/qrscan_task.c | 5 + nxp/.cproject | 2 +- nxp/board/board.c | 310 +++-- nxp/board/board.h | 51 +- nxp/board/pin_mux.c | 220 ++-- nxp/board/pin_mux.h | 254 ++-- nxp/drivers/fsl_lpspi.c | 2421 +++++++++++++++++++++++++++++++++++++++ nxp/drivers/fsl_lpspi.h | 1158 +++++++++++++++++++ nxp/nxp.mex | 238 ++-- nxp/source/nxp.c | 58 +- 15 files changed, 4422 insertions(+), 474 deletions(-) create mode 100644 app/screen/screen.c create mode 100644 app/screen/screen.h create mode 100644 app/screen/st7789.c create mode 100644 app/screen/st7789.h create mode 100644 nxp/drivers/fsl_lpspi.c create mode 100644 nxp/drivers/fsl_lpspi.h diff --git a/app/hal.h b/app/hal.h index d21e365..ad013dc 100644 --- a/app/hal.h +++ b/app/hal.h @@ -36,10 +36,16 @@ hal_err_t hal_camera_stop(); hal_err_t hal_camera_next_frame(uint8_t** fb); hal_err_t hal_camera_submit(uint8_t* fb); +// Screen +#define SCREEN_WIDTH 240 +#define SCREEN_HEIGHT 240 + // GPIO typedef enum { GPIO_CAMERA_PWDN = 0, GPIO_CAMERA_RST, + GPIO_LCD_CMD_DATA, + GPIO_LCD_RST, } hal_gpio_pin_t; typedef enum { @@ -63,6 +69,14 @@ typedef enum { hal_err_t hal_uart_send(hal_uart_port_t port, const uint8_t* data, size_t len); +// SPI +typedef enum { + SPI_LCD +} hal_spi_port_t; + +hal_err_t hal_spi_send(hal_spi_port_t port, const uint8_t* data, size_t len); +hal_err_t hal_spi_send_dma(hal_spi_port_t port, const uint8_t* data, size_t len); + // Crypto (only use in crypto library) hal_err_t hal_rng_next(uint8_t *buf, size_t len); diff --git a/app/screen/screen.c b/app/screen/screen.c new file mode 100644 index 0000000..635a60b --- /dev/null +++ b/app/screen/screen.c @@ -0,0 +1 @@ +#include "screen.h" diff --git a/app/screen/screen.h b/app/screen/screen.h new file mode 100644 index 0000000..5a14d27 --- /dev/null +++ b/app/screen/screen.h @@ -0,0 +1,18 @@ +#ifndef _SCREEN_H_ +#define _SCREEN_H_ + +#include "hal.h" + +#define _SCREEN_MODEL ST7789 + +typedef struct { + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; +} screen_area_t; + +hal_err_t screen_init(); +hal_err_t screen_draw_area(screen_area_t* area, uint16_t* pixels); + +#endif diff --git a/app/screen/st7789.c b/app/screen/st7789.c new file mode 100644 index 0000000..974d834 --- /dev/null +++ b/app/screen/st7789.c @@ -0,0 +1,61 @@ +#include "screen.h" +#include "st7789.h" +#include "FreeRTOS.h" +#include "task.h" + +#if (_SCREEN_MODEL == ST7789) + +hal_err_t st7789_write_cmd(uint8_t cmd) { + hal_gpio_set(GPIO_LCD_CMD_DATA, GPIO_RESET); + return hal_spi_send(SPI_LCD, &cmd, 1); +} + +hal_err_t st7789_write_params(const uint8_t* params, size_t len) { + hal_gpio_set(GPIO_LCD_CMD_DATA, GPIO_SET); + return hal_spi_send(SPI_LCD, params, len); +} + +static inline hal_err_t st7789_set_reg8(uint8_t reg, uint8_t value) { + if (st7789_write_cmd(reg) != HAL_OK) { + return HAL_ERROR; + } + + return st7789_write_params(&value, 1); +} + +hal_err_t screen_init() { + hal_gpio_set(GPIO_LCD_RST, GPIO_RESET); + hal_delay_us(ST7789_RST_PULSE_US); + hal_gpio_set(GPIO_LCD_RST, GPIO_SET); + vTaskDelay(pdMS_TO_TICKS(ST7789_CMD_DELAY_MS)); + + if (st7789_write_cmd(ST7789_SLPOUT) != HAL_OK) { + return HAL_ERROR; + } + + vTaskDelay(pdMS_TO_TICKS(ST7789_CMD_DELAY_MS)); + + if (st7789_set_reg8(ST7789_COLMOD, ST7789_COLOR_MODE_65K | ST7789_COLOR_MODE_16BIT) != HAL_OK) { + return HAL_ERROR; + } + + if (st7789_set_reg8(ST7789_MADCTL, ST7789_MADCTL_RGB) != HAL_OK) { + return HAL_ERROR; + } + + if (st7789_write_cmd(ST7789_INVOFF) != HAL_OK) { + return HAL_ERROR; + } + + if (st7789_write_cmd(ST7789_NORON) != HAL_OK) { + return HAL_ERROR; + } + + return st7789_write_cmd(ST7789_DISPON); +} + +hal_err_t screen_draw_area(screen_area_t* area, uint16_t* pixels) { + return HAL_ERROR; +} + +#endif diff --git a/app/screen/st7789.h b/app/screen/st7789.h new file mode 100644 index 0000000..1dd89f1 --- /dev/null +++ b/app/screen/st7789.h @@ -0,0 +1,85 @@ +#ifndef _ST7789_H_ +#define _ST7789_H_ + + +#include + +#define ST7789_CMD_DELAY_MS 10 +#define ST7789_RST_PULSE_US 12 + +#define ST7789_NOP0x00 +#define ST7789_SWRESET 0x01 +#define ST7789_RDDID 0x04 +#define ST7789_RDDST 0x09 + +#define ST7789_SLPIN 0x10 +#define ST7789_SLPOUT 0x11 +#define ST7789_PTLON 0x12 +#define ST7789_NORON 0x13 + +#define ST7789_INVOFF 0x20 +#define ST7789_INVON 0x21 +#define ST7789_DISPOFF 0x28 +#define ST7789_DISPON 0x29 +#define ST7789_CASET 0x2A +#define ST7789_RASET 0x2B +#define ST7789_RAMWR 0x2C +#define ST7789_RAMRD 0x2E + +#define ST7789_PTLAR 0x30 +#define ST7789_COLMOD 0x3A +#define ST7789_MADCTL 0x36 + +#define ST7789_MADCTL_MY 0x80 // Page Address Order +#define ST7789_MADCTL_MX 0x40 // Column Address Order +#define ST7789_MADCTL_MV 0x20 // Page/Column Order +#define ST7789_MADCTL_ML 0x10 // Line Address Order +#define ST7789_MADCTL_MH 0x04 // Display Data Latch Order +#define ST7789_MADCTL_RGB 0x00 +#define ST7789_MADCTL_BGR 0x08 + +#define ST7789_RDID1 0xDA +#define ST7789_RDID2 0xDB +#define ST7789_RDID3 0xDC +#define ST7789_RDID4 0xDD + +// color modes +#define ST7789_COLOR_MODE_65K 0x50 +#define ST7789_COLOR_MODE_262K 0x60 +#define ST7789_COLOR_MODE_12BIT 0x03 +#define ST7789_COLOR_MODE_16BIT 0x05 +#define ST7789_COLOR_MODE_18BIT 0x06 +#define ST7789_COLOR_MODE_16M 0x07 + +// Color definitions + +#define ST_R_POS_RGB 11 // Red last bit position for RGB display +#define ST_G_POS_RGB 5 // Green last bit position for RGB display +#define ST_B_POS_RGB 0 // Blue last bit position for RGB display + +#define ST_RGB(R,G,B) \ + (((uint16_t)(R >> 3) << ST_R_POS_RGB) | \ + ((uint16_t)(G >> 2) << ST_G_POS_RGB) | \ + ((uint16_t)(B >> 3) << ST_B_POS_RGB)) + +#define ST_COLOR_BLACK ST_RGB(0, 0, 0) +#define ST_COLOR_NAVY ST_RGB(0, 0, 123) +#define ST_COLOR_DARKGREEN ST_RGB(0, 125, 0) +#define ST_COLOR_DARKCYAN ST_RGB(0, 125, 123) +#define ST_COLOR_MAROON ST_RGB(123, 0, 0) +#define ST_COLOR_PURPLE ST_RGB(123, 0, 123) +#define ST_COLOR_OLIVE ST_RGB(123, 125, 0) +#define ST_COLOR_LIGHTGREY ST_RGB(198, 195, 198) +#define ST_COLOR_DARKGREY ST_RGB(123, 125, 123) +#define ST_COLOR_BLUE ST_RGB(0, 0, 255) +#define ST_COLOR_GREEN ST_RGB(0, 255, 0) +#define ST_COLOR_CYAN ST_RGB(0, 255, 255) +#define ST_COLOR_RED ST_RGB(255, 0, 0) +#define ST_COLOR_MAGENTA ST_RGB(255, 0, 255) +#define ST_COLOR_YELLOW ST_RGB(255, 255, 0) +#define ST_COLOR_WHITE ST_RGB(255, 255, 255) +#define ST_COLOR_ORANGE ST_RGB(255, 165, 0) +#define ST_COLOR_GREENYELLOW ST_RGB(173, 255, 41) +#define ST_COLOR_PINK ST_RGB(255, 130, 198) + +#endif diff --git a/app/tasks/qrscan_task.c b/app/tasks/qrscan_task.c index 96c4fd8..39e80a3 100644 --- a/app/tasks/qrscan_task.c +++ b/app/tasks/qrscan_task.c @@ -5,6 +5,7 @@ #include "qrcode/qrcode.h" #include "ur/ur.h" #include "ur/eip4527_decode.h" +#include "screen/screen.h" static struct quirc_code qrcode; static struct quirc_data qrdata; @@ -20,6 +21,10 @@ void qrscan_task_entry(void* pvParameters) { goto fail; } + if (screen_init() != HAL_OK) { + LOG_MSG("Failed to init screen"); + } + while (1) { uint8_t* fb; if (camera_next_frame(&fb) != HAL_OK) { diff --git a/nxp/.cproject b/nxp/.cproject index 001d2de..9f429e4 100644 --- a/nxp/.cproject +++ b/nxp/.cproject @@ -712,7 +712,7 @@ SDK_2.x_EVK-MIMXRT1064 2.13.0 - platform.drivers.clock.MIMXRT1064;platform.drivers.xip_device.MIMXRT1064;platform.drivers.igpio.MIMXRT1064;platform.drivers.common.MIMXRT1064;platform.drivers.lpuart.MIMXRT1064;platform.drivers.iomuxc.MIMXRT1064;platform.drivers.lpi2c.MIMXRT1064;platform.drivers.trng.MIMXRT1064;platform.drivers.csi.MIMXRT1064;device.MIMXRT1064_CMSIS.MIMXRT1064;device.MIMXRT1064_system.MIMXRT1064;CMSIS_Include_core_cm.MIMXRT1064;platform.drivers.xip_board.evkmimxrt1064.MIMXRT1064;project_template.evkmimxrt1064.MIMXRT1064;device.MIMXRT1064_startup.MIMXRT1064;platform.drivers.dcp.MIMXRT1064;middleware.baremetal.MIMXRT1064;platform.drivers.flexio.MIMXRT1064; + platform.drivers.clock.MIMXRT1064;platform.drivers.xip_device.MIMXRT1064;platform.drivers.igpio.MIMXRT1064;platform.drivers.common.MIMXRT1064;platform.drivers.lpuart.MIMXRT1064;platform.drivers.iomuxc.MIMXRT1064;platform.drivers.lpi2c.MIMXRT1064;platform.drivers.trng.MIMXRT1064;platform.drivers.csi.MIMXRT1064;device.MIMXRT1064_CMSIS.MIMXRT1064;device.MIMXRT1064_system.MIMXRT1064;CMSIS_Include_core_cm.MIMXRT1064;platform.drivers.xip_board.evkmimxrt1064.MIMXRT1064;device.MIMXRT1064_startup.MIMXRT1064;platform.drivers.dcp.MIMXRT1064;platform.drivers.flexio.MIMXRT1064;platform.drivers.lpspi.MIMXRT1064; evkmimxrt1064 MIMXRT1064DVL6A cm7 diff --git a/nxp/board/board.c b/nxp/board/board.c index 7429fd4..0c9af56 100644 --- a/nxp/board/board.c +++ b/nxp/board/board.c @@ -8,10 +8,10 @@ #include "fsl_common.h" #include "fsl_lpuart.h" #include "board.h" -#if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED #include "fsl_lpi2c.h" -#endif /* SDK_I2C_BASED_COMPONENT_USED */ #include "fsl_iomuxc.h" +#include "fsl_trng.h" +#include "fsl_gpt.h" /******************************************************************************* * Variables @@ -22,197 +22,179 @@ ******************************************************************************/ /* Initialize debug console. */ -void BOARD_InitDebugConsole(void) -{ - lpuart_config_t cfg; - LPUART_GetDefaultConfig(&cfg); - cfg.baudRate_Bps = BOARD_DEBUG_UART_BAUDRATE; - cfg.enableTx = 1; - LPUART_Init(BOARD_DEBUG_UART_BASEADDR, &cfg, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT); +void BOARD_InitDebugConsole(void) { + lpuart_config_t cfg; + LPUART_GetDefaultConfig(&cfg); + cfg.baudRate_Bps = BOARD_DEBUG_UART_BAUDRATE; + cfg.enableTx = 1; + LPUART_Init(BOARD_DEBUG_UART_BASEADDR, &cfg, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT); } -#if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED -void BOARD_LPI2C_Init(LPI2C_Type *base, uint32_t clkSrc_Hz) -{ - lpi2c_master_config_t lpi2cConfig = {0}; - LPI2C_MasterGetDefaultConfig(&lpi2cConfig); - LPI2C_MasterInit(base, &lpi2cConfig, clkSrc_Hz); +void BOARD_IO_Init() { + lpi2c_master_config_t lpi2cConfig = {0}; + LPI2C_MasterGetDefaultConfig(&lpi2cConfig); + LPI2C_MasterInit(BOARD_CAMERA_I2C_BASEADDR, &lpi2cConfig, BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT); + + lpspi_master_config_t lpspiConfig = {0}; + LPSPI_MasterGetDefaultConfig(&lpspiConfig); + lpspiConfig.baudRate = BOARD_LCD_BAUD_RATE; + lpspiConfig.pinCfg = kLPSPI_SdoInSdoOut; + lpspiConfig.cpol = kLPSPI_ClockPolarityActiveLow; + LPSPI_MasterInit(BOARD_LCD_SPI_BASEADDR, &lpspiConfig, BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT); } -status_t BOARD_LPI2C_Send(LPI2C_Type *base, - uint8_t deviceAddress, - uint32_t subAddress, - uint8_t subAddressSize, - uint8_t *txBuff, - uint8_t txBuffSize) -{ - lpi2c_master_transfer_t xfer; +void BOARD_Crypto_Init(dcp_handle_t* sha256_handle) { + trng_config_t trngConfig; + TRNG_GetDefaultConfig(&trngConfig); + TRNG_Init(TRNG, &trngConfig); - xfer.flags = kLPI2C_TransferDefaultFlag; - xfer.slaveAddress = deviceAddress; - xfer.direction = kLPI2C_Write; - xfer.subaddress = subAddress; - xfer.subaddressSize = subAddressSize; - xfer.data = txBuff; - xfer.dataSize = txBuffSize; - - return LPI2C_MasterTransferBlocking(base, &xfer); + dcp_config_t dcpConfig; + DCP_GetDefaultConfig(&dcpConfig); + DCP_Init(DCP, &dcpConfig); + sha256_handle->channel = kDCP_Channel0; } -status_t BOARD_LPI2C_Receive(LPI2C_Type *base, - uint8_t deviceAddress, - uint32_t subAddress, - uint8_t subAddressSize, - uint8_t *rxBuff, - uint8_t rxBuffSize) -{ - lpi2c_master_transfer_t xfer; - - xfer.flags = kLPI2C_TransferDefaultFlag; - xfer.slaveAddress = deviceAddress; - xfer.direction = kLPI2C_Read; - xfer.subaddress = subAddress; - xfer.subaddressSize = subAddressSize; - xfer.data = rxBuff; - xfer.dataSize = rxBuffSize; - - return LPI2C_MasterTransferBlocking(base, &xfer); +void BOARD_Timer_Init() { + gpt_config_t gptCfg; + GPT_GetDefaultConfig(&gptCfg); + gptCfg.clockSource = kGPT_ClockSource_Osc; + gptCfg.enableFreeRun = true; + gptCfg.enableMode = true; + gptCfg.divider = 24; + GPT_Init(GPT1, &gptCfg); } -#endif /* SDK_I2C_BASED_COMPONENT_USED */ /* MPU configuration. */ -void BOARD_ConfigMPU(void) -{ +void BOARD_ConfigMPU(void) { #if defined(__CC_ARM) || defined(__ARMCC_VERSION) - extern uint32_t Image$$RW_m_ncache$$Base[]; - /* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */ - extern uint32_t Image$$RW_m_ncache_unused$$Base[]; - extern uint32_t Image$$RW_m_ncache_unused$$ZI$$Limit[]; - uint32_t nonCacheStart = (uint32_t)Image$$RW_m_ncache$$Base; - uint32_t size = ((uint32_t)Image$$RW_m_ncache_unused$$Base == nonCacheStart) ? - 0 : - ((uint32_t)Image$$RW_m_ncache_unused$$ZI$$Limit - nonCacheStart); + extern uint32_t Image$$RW_m_ncache$$Base[]; + /* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */ + extern uint32_t Image$$RW_m_ncache_unused$$Base[]; + extern uint32_t Image$$RW_m_ncache_unused$$ZI$$Limit[]; + uint32_t nonCacheStart = (uint32_t)Image$$RW_m_ncache$$Base; + uint32_t size = ((uint32_t)Image$$RW_m_ncache_unused$$Base == nonCacheStart) ? + 0 : + ((uint32_t)Image$$RW_m_ncache_unused$$ZI$$Limit - nonCacheStart); #elif defined(__MCUXPRESSO) - extern uint32_t __base_NCACHE_REGION; - extern uint32_t __top_NCACHE_REGION; - uint32_t nonCacheStart = (uint32_t)(&__base_NCACHE_REGION); - uint32_t size = (uint32_t)(&__top_NCACHE_REGION) - nonCacheStart; + extern uint32_t __base_NCACHE_REGION; + extern uint32_t __top_NCACHE_REGION; + uint32_t nonCacheStart = (uint32_t)(&__base_NCACHE_REGION); + __attribute__((unused)) uint32_t size = (uint32_t)(&__top_NCACHE_REGION) - nonCacheStart; #elif defined(__ICCARM__) || defined(__GNUC__) - extern uint32_t __NCACHE_REGION_START[]; - extern uint32_t __NCACHE_REGION_SIZE[]; - uint32_t nonCacheStart = (uint32_t)__NCACHE_REGION_START; - uint32_t size = (uint32_t)__NCACHE_REGION_SIZE; + extern uint32_t __NCACHE_REGION_START[]; + extern uint32_t __NCACHE_REGION_SIZE[]; + uint32_t nonCacheStart = (uint32_t)__NCACHE_REGION_START; + uint32_t size = (uint32_t)__NCACHE_REGION_SIZE; #endif - /* Disable I cache and D cache */ - if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)) - { - SCB_DisableICache(); - } - if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR)) - { - SCB_DisableDCache(); - } + /* Disable I cache and D cache */ + if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)) { + SCB_DisableICache(); + } - /* Disable MPU */ - ARM_MPU_Disable(); + if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR)) { + SCB_DisableDCache(); + } - /* MPU configure: - * Use ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, - * SubRegionDisable, Size) - * API in mpu_armv7.h. - * param DisableExec Instruction access (XN) disable bit,0=instruction fetches enabled, 1=instruction fetches - * disabled. - * param AccessPermission Data access permissions, allows you to configure read/write access for User and - * Privileged mode. - * Use MACROS defined in mpu_armv7.h: - * ARM_MPU_AP_NONE/ARM_MPU_AP_PRIV/ARM_MPU_AP_URO/ARM_MPU_AP_FULL/ARM_MPU_AP_PRO/ARM_MPU_AP_RO - * Combine TypeExtField/IsShareable/IsCacheable/IsBufferable to configure MPU memory access attributes. - * TypeExtField IsShareable IsCacheable IsBufferable Memory Attribute Shareability Cache - * 0 x 0 0 Strongly Ordered shareable - * 0 x 0 1 Device shareable - * 0 0 1 0 Normal not shareable Outer and inner write - * through no write allocate - * 0 0 1 1 Normal not shareable Outer and inner write - * back no write allocate - * 0 1 1 0 Normal shareable Outer and inner write - * through no write allocate - * 0 1 1 1 Normal shareable Outer and inner write - * back no write allocate - * 1 0 0 0 Normal not shareable outer and inner - * noncache - * 1 1 0 0 Normal shareable outer and inner - * noncache - * 1 0 1 1 Normal not shareable outer and inner write - * back write/read acllocate - * 1 1 1 1 Normal shareable outer and inner write - * back write/read acllocate - * 2 x 0 0 Device not shareable - * Above are normal use settings, if your want to see more details or want to config different inner/outter cache - * policy. - * please refer to Table 4-55 /4-56 in arm cortex-M7 generic user guide - * param SubRegionDisable Sub-region disable field. 0=sub-region is enabled, 1=sub-region is disabled. - * param Size Region size of the region to be configured. use ARM_MPU_REGION_SIZE_xxx MACRO in - * mpu_armv7.h. - */ - /* - * Add default region to deny access to whole address space to workaround speculative prefetch. - * Refer to Arm errata 1013783-B for more details. - * - */ - /* Region 0 setting: Instruction access disabled, No data access permission. */ - MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U); - MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 0, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB); + /* Disable MPU */ + ARM_MPU_Disable(); - /* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */ - MPU->RBAR = ARM_MPU_RBAR(1, 0x80000000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); + /* MPU configure: + * Use ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, + * SubRegionDisable, Size) + * API in mpu_armv7.h. + * param DisableExec Instruction access (XN) disable bit,0=instruction fetches enabled, 1=instruction fetches + * disabled. + * param AccessPermission Data access permissions, allows you to configure read/write access for User and + * Privileged mode. + * Use MACROS defined in mpu_armv7.h: + * ARM_MPU_AP_NONE/ARM_MPU_AP_PRIV/ARM_MPU_AP_URO/ARM_MPU_AP_FULL/ARM_MPU_AP_PRO/ARM_MPU_AP_RO + * Combine TypeExtField/IsShareable/IsCacheable/IsBufferable to configure MPU memory access attributes. + * TypeExtField IsShareable IsCacheable IsBufferable Memory Attribute Shareability Cache + * 0 x 0 0 Strongly Ordered shareable + * 0 x 0 1 Device shareable + * 0 0 1 0 Normal not shareable Outer and inner write + * through no write allocate + * 0 0 1 1 Normal not shareable Outer and inner write + * back no write allocate + * 0 1 1 0 Normal shareable Outer and inner write + * through no write allocate + * 0 1 1 1 Normal shareable Outer and inner write + * back no write allocate + * 1 0 0 0 Normal not shareable outer and inner + * noncache + * 1 1 0 0 Normal shareable outer and inner + * noncache + * 1 0 1 1 Normal not shareable outer and inner write + * back write/read acllocate + * 1 1 1 1 Normal shareable outer and inner write + * back write/read acllocate + * 2 x 0 0 Device not shareable + * Above are normal use settings, if your want to see more details or want to config different inner/outter cache + * policy. + * please refer to Table 4-55 /4-56 in arm cortex-M7 generic user guide + * param SubRegionDisable Sub-region disable field. 0=sub-region is enabled, 1=sub-region is disabled. + * param Size Region size of the region to be configured. use ARM_MPU_REGION_SIZE_xxx MACRO in + * mpu_armv7.h. + */ + /* + * Add default region to deny access to whole address space to workaround speculative prefetch. + * Refer to Arm errata 1013783-B for more details. + * + */ + /* Region 0 setting: Instruction access disabled, No data access permission. */ + MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U); + MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 0, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB); - /* Region 2 setting: Memory with Device type, not shareable, non-cacheable. */ - MPU->RBAR = ARM_MPU_RBAR(2, 0x60000000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); + /* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */ + MPU->RBAR = ARM_MPU_RBAR(1, 0x80000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); + + /* Region 2 setting: Memory with Device type, not shareable, non-cacheable. */ + MPU->RBAR = ARM_MPU_RBAR(2, 0x60000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); #if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1) - /* Region 3 setting: Memory with Normal type, not shareable, outer/inner write back. */ - MPU->RBAR = ARM_MPU_RBAR(3, 0x70000000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_4MB); + /* Region 3 setting: Memory with Normal type, not shareable, outer/inner write back. */ + MPU->RBAR = ARM_MPU_RBAR(3, 0x70000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_4MB); #endif - /* Region 4 setting: Memory with Device type, not shareable, non-cacheable. */ - MPU->RBAR = ARM_MPU_RBAR(4, 0x00000000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB); + /* Region 4 setting: Memory with Device type, not shareable, non-cacheable. */ + MPU->RBAR = ARM_MPU_RBAR(4, 0x00000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB); - /* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back */ - MPU->RBAR = ARM_MPU_RBAR(5, 0x00000000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); + /* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back */ + MPU->RBAR = ARM_MPU_RBAR(5, 0x00000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); - /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back */ - MPU->RBAR = ARM_MPU_RBAR(6, 0x20000000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); + /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back */ + MPU->RBAR = ARM_MPU_RBAR(6, 0x20000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); - /* Region 7 setting: Memory with Normal type, not shareable, outer/inner write back */ - MPU->RBAR = ARM_MPU_RBAR(7, 0x20200000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 0, 1, 0, ARM_MPU_REGION_SIZE_512KB); + /* Region 7 setting: Memory with Normal type, not shareable, outer/inner write back */ + MPU->RBAR = ARM_MPU_RBAR(7, 0x20200000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 0, 1, 0, ARM_MPU_REGION_SIZE_512KB); - /* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back */ - MPU->RBAR = ARM_MPU_RBAR(8, 0x20280000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 0, 1, 0, ARM_MPU_REGION_SIZE_256KB); + /* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back */ + MPU->RBAR = ARM_MPU_RBAR(8, 0x20280000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 0, 1, 0, ARM_MPU_REGION_SIZE_256KB); - /* Region 9 setting: Memory with Normal type, not shareable, outer/inner write back */ - MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_32MB); + /* Region 9 setting: Memory with Normal type, not shareable, outer/inner write back */ + MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_32MB); - /* Region 10 setting: Memory with Device type, not shareable, non-cacheable */ - MPU->RBAR = ARM_MPU_RBAR(10, 0x40000000); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4MB); + /* Region 10 setting: Memory with Device type, not shareable, non-cacheable */ + MPU->RBAR = ARM_MPU_RBAR(10, 0x40000000); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4MB); - /* Region 11 setting: Memory with Device type, not shareable, non-cacheable */ - MPU->RBAR = ARM_MPU_RBAR(11, 0x42000000); - MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1MB); + /* Region 11 setting: Memory with Device type, not shareable, non-cacheable */ + MPU->RBAR = ARM_MPU_RBAR(11, 0x42000000); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1MB); - /* Enable MPU */ - ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk); + /* Enable MPU */ + ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk); - /* Enable I cache and D cache */ - SCB_EnableDCache(); - SCB_EnableICache(); + /* Enable I cache and D cache */ + SCB_EnableDCache(); + SCB_EnableICache(); } diff --git a/nxp/board/board.h b/nxp/board/board.h index c66535b..ea571eb 100644 --- a/nxp/board/board.h +++ b/nxp/board/board.h @@ -12,19 +12,15 @@ #include "fsl_common.h" #include "fsl_gpio.h" #include "fsl_clock.h" +#include "fsl_dcp.h" +#include "fsl_lpspi.h" +#include "pin_mux.h" /******************************************************************************* * Definitions ******************************************************************************/ -/*! @brief The board name */ -#define BOARD_NAME "MIMXRT1064-EVK" - /* The UART to use for debug messages. */ -#define BOARD_DEBUG_UART_BASEADDR LPUART1 -#define BOARD_DEBUG_UART_INSTANCE 1U - -#define BOARD_UART_IRQ LPUART1_IRQn -#define BOARD_UART_IRQ_HANDLER LPUART1_IRQHandler +#define BOARD_DEBUG_UART_BASEADDR BOARD_INITDEBUG_UART_UART1_TXD_PERIPHERAL #ifndef BOARD_DEBUG_UART_BAUDRATE #define BOARD_DEBUG_UART_BAUDRATE (115200U) @@ -34,10 +30,24 @@ #define BOARD_FLASH_SIZE (0x400000U) /* @Brief Board CAMERA configuration */ -#define BOARD_CAMERA_I2C_BASEADDR LPI2C1 +#define BOARD_CAMERA_I2C_BASEADDR BOARD_INITCAMERA_CSI_I2C_SDA_PERIPHERAL -#define BOARD_CAMERA_PWDN_GPIO GPIO1 -#define BOARD_CAMERA_PWDN_PIN 18 +#define BOARD_CAMERA_PWDN_GPIO BOARD_INITCAMERA_CSI_PWDN_PERIPHERAL +#define BOARD_CAMERA_PWDN_PIN BOARD_INITCAMERA_CSI_PWDN_CHANNEL + +#define BOARD_CAMERA_RST_GPIO NULL +#define BOARD_CAMERA_RST_PIN 0 + +/* @Brief Board LCD configuration */ +#define BOARD_LCD_SPI_BASEADDR BOARD_INITLCD_SD1_CMD_PERIPHERAL + +#define BOARD_LCD_RST_GPIO BOARD_INITLCD_LCD_RESET_GPIO +#define BOARD_LCD_RST_PIN BOARD_INITLCD_LCD_RESET_GPIO_PIN + +#define BOARD_LCD_CD_GPIO BOARD_INITLCD_LCD_CD_GPIO +#define BOARD_LCD_CD_PIN BOARD_INITLCD_LCD_CD_GPIO_PIN + +#define BOARD_LCD_BAUD_RATE 5000000 #if defined(__cplusplus) extern "C" { @@ -51,21 +61,10 @@ uint32_t BOARD_DebugConsoleSrcFreq(void); void BOARD_InitDebugConsole(void); void BOARD_ConfigMPU(void); -#if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED -void BOARD_LPI2C_Init(LPI2C_Type *base, uint32_t clkSrc_Hz); -status_t BOARD_LPI2C_Send(LPI2C_Type *base, - uint8_t deviceAddress, - uint32_t subAddress, - uint8_t subaddressSize, - uint8_t *txBuff, - uint8_t txBuffSize); -status_t BOARD_LPI2C_Receive(LPI2C_Type *base, - uint8_t deviceAddress, - uint32_t subAddress, - uint8_t subaddressSize, - uint8_t *rxBuff, - uint8_t rxBuffSize); -#endif + +void BOARD_IO_Init(); +void BOARD_Crypto_Init(dcp_handle_t* sha256_handle); +void BOARD_Timer_Init(); #if defined(__cplusplus) } #endif /* __cplusplus */ diff --git a/nxp/board/pin_mux.c b/nxp/board/pin_mux.c index 2a493a8..67e71e3 100644 --- a/nxp/board/pin_mux.c +++ b/nxp/board/pin_mux.c @@ -109,7 +109,7 @@ pin_labels: - {pin_num: L10, pin_signal: GPIO_AD_B0_15, label: 'CAN2_RX/U12[4]', identifier: CAN2_RX} - {pin_num: J11, pin_signal: GPIO_AD_B1_00, label: 'I2C1_SCL/CSI_I2C_SCL/J35[20]/J23[6]/U13[17]/U32[4]', identifier: I2C_SCL_FXOS8700CQ;CSI_I2C_SCL} - {pin_num: K11, pin_signal: GPIO_AD_B1_01, label: 'I2C1_SDA/CSI_I2C_SDA/J35[22]/J23[5]/U13[18]/U32[6]', identifier: I2C_SDA_FXOS8700CQ;CSI_I2C_SDA} -- {pin_num: L11, pin_signal: GPIO_AD_B1_02, label: CSI_PWDN, identifier: SPDIF_OUT;CSI_PWDN} +- {pin_num: L11, pin_signal: GPIO_AD_B1_02, label: CSI_PWDN, identifier: CSI_PWDN} - {pin_num: M12, pin_signal: GPIO_AD_B1_03, label: 'SPDIF_IN/J22[8]', identifier: SPDIF_IN} - {pin_num: H13, pin_signal: GPIO_AD_B1_08, label: 'AUD_INT/CSI_D9//J35[13]/J22[4]', identifier: CSI_D9} - {pin_num: M13, pin_signal: GPIO_AD_B1_09, label: 'SAI1_MCLK/CSI_D8/J35[11]', identifier: CSI_D8} @@ -120,9 +120,9 @@ pin_labels: - {pin_num: G12, pin_signal: GPIO_AD_B1_14, label: 'SAI1_TX_BCLK/CSI_D3/J35[4]/U13[12]', identifier: CSI_D3} - {pin_num: J14, pin_signal: GPIO_AD_B1_15, label: 'SAI1_TX_SYNC/CSI_D2/J35[6]/U13[13]', identifier: CSI_D2} - {pin_num: J4, pin_signal: GPIO_SD_B0_00, label: 'SD1_CMD/J24[6]', identifier: SD1_CMD} -- {pin_num: J3, pin_signal: GPIO_SD_B0_01, label: 'SD1_CLK/J24[3]', identifier: SD1_CLK} +- {pin_num: J3, pin_signal: GPIO_SD_B0_01, label: 'SD1_CLK/J24[3]', identifier: SD1_CLK;LCD_CD} - {pin_num: J1, pin_signal: GPIO_SD_B0_02, label: 'SD1_D0/J24[4]/SPI_MOSI/PWM', identifier: SD1_D0} -- {pin_num: K1, pin_signal: GPIO_SD_B0_03, label: 'SD1_D1/J24[5]/SPI_MISO', identifier: SD1_D1} +- {pin_num: K1, pin_signal: GPIO_SD_B0_03, label: 'SD1_D1/J24[5]/SPI_MISO', identifier: SD1_D1;LCD_RESET} - {pin_num: H2, pin_signal: GPIO_SD_B0_04, label: SD1_D2, identifier: SD1_D2} - {pin_num: J2, pin_signal: GPIO_SD_B0_05, label: SD1_D3, identifier: SD1_D3} - {pin_num: L5, pin_signal: GPIO_SD_B1_00, label: FlexSPI_D3_B, identifier: FlexSPI_D3_B} @@ -221,13 +221,15 @@ pin_labels: * * END ****************************************************************************************************************/ void BOARD_InitBootPins(void) { - BOARD_InitPins(); - BOARD_InitCSI(); + BOARD_InitISO7816(); + BOARD_InitCamera(); + BOARD_InitLCD(); + BOARD_InitKeyboard(); } /* * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* -BOARD_InitPins: +BOARD_InitISO7816: - options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'} - pin_list: [] * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** @@ -235,11 +237,146 @@ BOARD_InitPins: /* FUNCTION ************************************************************************************************************ * - * Function Name : BOARD_InitPins + * Function Name : BOARD_InitISO7816 * Description : Configures pin routing and optionally pin electrical features. * * END ****************************************************************************************************************/ -void BOARD_InitPins(void) { +void BOARD_InitISO7816(void) { +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitCamera: +- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: H13, peripheral: CSI, signal: 'csi_data, 09', pin_signal: GPIO_AD_B1_08} + - {pin_num: M13, peripheral: CSI, signal: 'csi_data, 08', pin_signal: GPIO_AD_B1_09} + - {pin_num: L13, peripheral: CSI, signal: 'csi_data, 07', pin_signal: GPIO_AD_B1_10} + - {pin_num: J13, peripheral: CSI, signal: 'csi_data, 06', pin_signal: GPIO_AD_B1_11} + - {pin_num: H12, peripheral: CSI, signal: 'csi_data, 05', pin_signal: GPIO_AD_B1_12} + - {pin_num: H11, peripheral: CSI, signal: 'csi_data, 04', pin_signal: GPIO_AD_B1_13} + - {pin_num: J14, peripheral: CSI, signal: 'csi_data, 02', pin_signal: GPIO_AD_B1_15} + - {pin_num: G12, peripheral: CSI, signal: 'csi_data, 03', pin_signal: GPIO_AD_B1_14} + - {pin_num: L12, peripheral: CSI, signal: csi_pixclk, pin_signal: GPIO_AD_B1_04} + - {pin_num: K12, peripheral: CSI, signal: csi_mclk, pin_signal: GPIO_AD_B1_05} + - {pin_num: J12, peripheral: CSI, signal: csi_vsync, pin_signal: GPIO_AD_B1_06} + - {pin_num: K10, peripheral: CSI, signal: csi_hsync, pin_signal: GPIO_AD_B1_07} + - {pin_num: J11, peripheral: LPI2C1, signal: SCL, pin_signal: GPIO_AD_B1_00, identifier: CSI_I2C_SCL, software_input_on: Enable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_22K_Ohm, + pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Enable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow} + - {pin_num: K11, peripheral: LPI2C1, signal: SDA, pin_signal: GPIO_AD_B1_01, identifier: CSI_I2C_SDA, software_input_on: Enable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_22K_Ohm, + pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Enable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow} + - {pin_num: L11, peripheral: GPIO1, signal: 'gpio_io, 18', pin_signal: GPIO_AD_B1_02, direction: OUTPUT, gpio_init_state: no_init} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitCamera + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitCamera(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); + + /* GPIO configuration of CSI_PWDN on GPIO_AD_B1_02 (pin L11) */ + gpio_pin_config_t CSI_PWDN_config = { + .direction = kGPIO_DigitalOutput, + .outputLogic = 0U, + .interruptMode = kGPIO_NoIntmode + }; + /* Initialize GPIO functionality on GPIO_AD_B1_02 (pin L11) */ + GPIO_PinInit(GPIO1, 18U, &CSI_PWDN_config); + + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 1U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 1U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_02_GPIO1_IO18, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_04_CSI_PIXCLK, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_05_CSI_MCLK, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_06_CSI_VSYNC, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_07_CSI_HSYNC, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_08_CSI_DATA09, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_CSI_DATA08, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_10_CSI_DATA07, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_11_CSI_DATA06, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_12_CSI_DATA05, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_13_CSI_DATA04, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_14_CSI_DATA03, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_15_CSI_DATA02, 0U); + IOMUXC_GPR->GPR26 = ((IOMUXC_GPR->GPR26 & + (~(BOARD_INITCAMERA_IOMUXC_GPR_GPR26_GPIO_MUX1_GPIO_SEL_MASK))) + | IOMUXC_GPR_GPR26_GPIO_MUX1_GPIO_SEL(0x00U) + ); + IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0xD8B0U); + IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xD8B0U); +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitLCD: +- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: J1, peripheral: LPSPI1, signal: SDO, pin_signal: GPIO_SD_B0_02} + - {pin_num: J4, peripheral: LPSPI1, signal: SCK, pin_signal: GPIO_SD_B0_00} + - {pin_num: J3, peripheral: GPIO3, signal: 'gpio_io, 13', pin_signal: GPIO_SD_B0_01, identifier: LCD_CD, direction: OUTPUT, gpio_init_state: no_init} + - {pin_num: K1, peripheral: GPIO3, signal: 'gpio_io, 15', pin_signal: GPIO_SD_B0_03, identifier: LCD_RESET, direction: OUTPUT, gpio_init_state: 'true'} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitLCD + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitLCD(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); + + /* GPIO configuration of LCD_CD on GPIO_SD_B0_01 (pin J3) */ + gpio_pin_config_t LCD_CD_config = { + .direction = kGPIO_DigitalOutput, + .outputLogic = 0U, + .interruptMode = kGPIO_NoIntmode + }; + /* Initialize GPIO functionality on GPIO_SD_B0_01 (pin J3) */ + GPIO_PinInit(GPIO3, 13U, &LCD_CD_config); + + /* GPIO configuration of LCD_RESET on GPIO_SD_B0_03 (pin K1) */ + gpio_pin_config_t LCD_RESET_config = { + .direction = kGPIO_DigitalOutput, + .outputLogic = 1U, + .interruptMode = kGPIO_NoIntmode + }; + /* Initialize GPIO functionality on GPIO_SD_B0_03 (pin K1) */ + GPIO_PinInit(GPIO3, 15U, &LCD_RESET_config); + + IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B0_01_GPIO3_IO13, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B0_03_GPIO3_IO15, 0U); + IOMUXC_GPR->GPR28 = ((IOMUXC_GPR->GPR28 & + (~(BOARD_INITLCD_IOMUXC_GPR_GPR28_GPIO_MUX3_GPIO_SEL_MASK))) + | IOMUXC_GPR_GPR28_GPIO_MUX3_GPIO_SEL(0x00U) + ); +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitKeyboard: +- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'} +- pin_list: [] + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitKeyboard + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitKeyboard(void) { } @@ -270,73 +407,6 @@ void BOARD_InitDEBUG_UART(void) { IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0x10B0U); } - -/* - * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* -BOARD_InitCSI: -- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'} -- pin_list: - - {pin_num: H13, peripheral: CSI, signal: 'csi_data, 09', pin_signal: GPIO_AD_B1_08} - - {pin_num: M13, peripheral: CSI, signal: 'csi_data, 08', pin_signal: GPIO_AD_B1_09} - - {pin_num: L13, peripheral: CSI, signal: 'csi_data, 07', pin_signal: GPIO_AD_B1_10} - - {pin_num: J13, peripheral: CSI, signal: 'csi_data, 06', pin_signal: GPIO_AD_B1_11} - - {pin_num: H12, peripheral: CSI, signal: 'csi_data, 05', pin_signal: GPIO_AD_B1_12} - - {pin_num: H11, peripheral: CSI, signal: 'csi_data, 04', pin_signal: GPIO_AD_B1_13} - - {pin_num: J14, peripheral: CSI, signal: 'csi_data, 02', pin_signal: GPIO_AD_B1_15} - - {pin_num: G12, peripheral: CSI, signal: 'csi_data, 03', pin_signal: GPIO_AD_B1_14} - - {pin_num: L12, peripheral: CSI, signal: csi_pixclk, pin_signal: GPIO_AD_B1_04} - - {pin_num: K12, peripheral: CSI, signal: csi_mclk, pin_signal: GPIO_AD_B1_05} - - {pin_num: J12, peripheral: CSI, signal: csi_vsync, pin_signal: GPIO_AD_B1_06} - - {pin_num: K10, peripheral: CSI, signal: csi_hsync, pin_signal: GPIO_AD_B1_07} - - {pin_num: J11, peripheral: LPI2C1, signal: SCL, pin_signal: GPIO_AD_B1_00, identifier: CSI_I2C_SCL, software_input_on: Enable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_22K_Ohm, - pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Enable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow} - - {pin_num: K11, peripheral: LPI2C1, signal: SDA, pin_signal: GPIO_AD_B1_01, identifier: CSI_I2C_SDA, software_input_on: Enable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_22K_Ohm, - pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Enable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow} - - {pin_num: L11, peripheral: GPIO1, signal: 'gpio_io, 18', pin_signal: GPIO_AD_B1_02, identifier: CSI_PWDN, direction: OUTPUT, gpio_init_state: no_init} - * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** - */ - -/* FUNCTION ************************************************************************************************************ - * - * Function Name : BOARD_InitCSI - * Description : Configures pin routing and optionally pin electrical features. - * - * END ****************************************************************************************************************/ -void BOARD_InitCSI(void) { - CLOCK_EnableClock(kCLOCK_Iomuxc); - - /* GPIO configuration of CSI_PWDN on GPIO_AD_B1_02 (pin L11) */ - gpio_pin_config_t CSI_PWDN_config = { - .direction = kGPIO_DigitalOutput, - .outputLogic = 0U, - .interruptMode = kGPIO_NoIntmode - }; - /* Initialize GPIO functionality on GPIO_AD_B1_02 (pin L11) */ - GPIO_PinInit(GPIO1, 18U, &CSI_PWDN_config); - - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 1U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 1U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_02_GPIO1_IO18, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_04_CSI_PIXCLK, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_05_CSI_MCLK, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_06_CSI_VSYNC, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_07_CSI_HSYNC, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_08_CSI_DATA09, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_CSI_DATA08, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_10_CSI_DATA07, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_11_CSI_DATA06, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_12_CSI_DATA05, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_13_CSI_DATA04, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_14_CSI_DATA03, 0U); - IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_15_CSI_DATA02, 0U); - IOMUXC_GPR->GPR26 = ((IOMUXC_GPR->GPR26 & - (~(BOARD_INITCSI_IOMUXC_GPR_GPR26_GPIO_MUX1_GPIO_SEL_MASK))) - | IOMUXC_GPR_GPR26_GPIO_MUX1_GPIO_SEL(0x00U) - ); - IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0xD8B0U); - IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xD8B0U); -} - /*********************************************************************************************************************** * EOF **********************************************************************************************************************/ diff --git a/nxp/board/pin_mux.h b/nxp/board/pin_mux.h index 938a579..431786e 100644 --- a/nxp/board/pin_mux.h +++ b/nxp/board/pin_mux.h @@ -41,7 +41,159 @@ void BOARD_InitBootPins(void); * @brief Configures pin routing and optionally pin electrical features. * */ -void BOARD_InitPins(void); +void BOARD_InitISO7816(void); + +#define BOARD_INITCAMERA_IOMUXC_GPR_GPR26_GPIO_MUX1_GPIO_SEL_MASK 0x040000U /*!< GPIO1 and GPIO6 share same IO MUX function, GPIO_MUX1 selects one GPIO function: affected bits mask */ + +/* GPIO_AD_B1_08 (coord H13), AUD_INT/CSI_D9//J35[13]/J22[4] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_D9_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_D9_SIGNAL csi_data /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_D9_CHANNEL 9U /*!< Signal channel */ + +/* GPIO_AD_B1_09 (coord M13), SAI1_MCLK/CSI_D8/J35[11] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_D8_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_D8_SIGNAL csi_data /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_D8_CHANNEL 8U /*!< Signal channel */ + +/* GPIO_AD_B1_10 (coord L13), SAI1_RX_SYNC/CSI_D7/J35[9]/J23[1] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_D7_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_D7_SIGNAL csi_data /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_D7_CHANNEL 7U /*!< Signal channel */ + +/* GPIO_AD_B1_11 (coord J13), SAI1_RX_BCLK/CSI_D6/J35[7]/J23[2] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_D6_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_D6_SIGNAL csi_data /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_D6_CHANNEL 6U /*!< Signal channel */ + +/* GPIO_AD_B1_12 (coord H12), SAI1_RXD/CSI_D5/J35[5]/U13[16] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_D5_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_D5_SIGNAL csi_data /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_D5_CHANNEL 5U /*!< Signal channel */ + +/* GPIO_AD_B1_13 (coord H11), SAI1_TXD/CSI_D4/J35[3]/U13[14] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_D4_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_D4_SIGNAL csi_data /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_D4_CHANNEL 4U /*!< Signal channel */ + +/* GPIO_AD_B1_15 (coord J14), SAI1_TX_SYNC/CSI_D2/J35[6]/U13[13] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_D2_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_D2_SIGNAL csi_data /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_D2_CHANNEL 2U /*!< Signal channel */ + +/* GPIO_AD_B1_14 (coord G12), SAI1_TX_BCLK/CSI_D3/J35[4]/U13[12] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_D3_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_D3_SIGNAL csi_data /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_D3_CHANNEL 3U /*!< Signal channel */ + +/* GPIO_AD_B1_04 (coord L12), CSI_PIXCLK/J35[8]/J23[3] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_PIXCLK_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_PIXCLK_SIGNAL csi_pixclk /*!< Signal name */ + +/* GPIO_AD_B1_05 (coord K12), CSI_MCLK/J35[12]/J23[4] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_MCLK_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_MCLK_SIGNAL csi_mclk /*!< Signal name */ + +/* GPIO_AD_B1_06 (coord J12), CSI_VSYNC/J35[18]/J22[2]/UART_TX */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_VSYNC_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_VSYNC_SIGNAL csi_vsync /*!< Signal name */ + +/* GPIO_AD_B1_07 (coord K10), CSI_HSYNC/J35[16]/J22[1]/UART_RX */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_HSYNC_PERIPHERAL CSI /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_HSYNC_SIGNAL csi_hsync /*!< Signal name */ + +/* GPIO_AD_B1_00 (coord J11), I2C1_SCL/CSI_I2C_SCL/J35[20]/J23[6]/U13[17]/U32[4] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_I2C_SCL_PERIPHERAL LPI2C1 /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_I2C_SCL_SIGNAL SCL /*!< Signal name */ + +/* GPIO_AD_B1_01 (coord K11), I2C1_SDA/CSI_I2C_SDA/J35[22]/J23[5]/U13[18]/U32[6] */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_I2C_SDA_PERIPHERAL LPI2C1 /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_I2C_SDA_SIGNAL SDA /*!< Signal name */ + +/* GPIO_AD_B1_02 (coord L11), CSI_PWDN */ +/* Routed pin properties */ +#define BOARD_INITCAMERA_CSI_PWDN_PERIPHERAL GPIO1 /*!< Peripheral name */ +#define BOARD_INITCAMERA_CSI_PWDN_SIGNAL gpio_io /*!< Signal name */ +#define BOARD_INITCAMERA_CSI_PWDN_CHANNEL 18U /*!< Signal channel */ + +/* Symbols to be used with GPIO driver */ +#define BOARD_INITCAMERA_CSI_PWDN_GPIO GPIO1 /*!< GPIO peripheral base pointer */ +#define BOARD_INITCAMERA_CSI_PWDN_GPIO_PIN 18U /*!< GPIO pin number */ +#define BOARD_INITCAMERA_CSI_PWDN_GPIO_PIN_MASK (1U << 18U) /*!< GPIO pin mask */ +#define BOARD_INITCAMERA_CSI_PWDN_PORT GPIO1 /*!< PORT peripheral base pointer */ +#define BOARD_INITCAMERA_CSI_PWDN_PIN 18U /*!< PORT pin number */ +#define BOARD_INITCAMERA_CSI_PWDN_PIN_MASK (1U << 18U) /*!< PORT pin mask */ + +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitCamera(void); + +#define BOARD_INITLCD_IOMUXC_GPR_GPR28_GPIO_MUX3_GPIO_SEL_MASK 0xA000U /*!< GPIO3 and GPIO8 share same IO MUX function, GPIO_MUX3 selects one GPIO function: affected bits mask */ + +/* GPIO_SD_B0_02 (coord J1), SD1_D0/J24[4]/SPI_MOSI/PWM */ +/* Routed pin properties */ +#define BOARD_INITLCD_SD1_D0_PERIPHERAL LPSPI1 /*!< Peripheral name */ +#define BOARD_INITLCD_SD1_D0_SIGNAL SDO /*!< Signal name */ + +/* GPIO_SD_B0_00 (coord J4), SD1_CMD/J24[6] */ +/* Routed pin properties */ +#define BOARD_INITLCD_SD1_CMD_PERIPHERAL LPSPI1 /*!< Peripheral name */ +#define BOARD_INITLCD_SD1_CMD_SIGNAL SCK /*!< Signal name */ + +/* GPIO_SD_B0_01 (coord J3), SD1_CLK/J24[3] */ +/* Routed pin properties */ +#define BOARD_INITLCD_LCD_CD_PERIPHERAL GPIO3 /*!< Peripheral name */ +#define BOARD_INITLCD_LCD_CD_SIGNAL gpio_io /*!< Signal name */ +#define BOARD_INITLCD_LCD_CD_CHANNEL 13U /*!< Signal channel */ + +/* Symbols to be used with GPIO driver */ +#define BOARD_INITLCD_LCD_CD_GPIO GPIO3 /*!< GPIO peripheral base pointer */ +#define BOARD_INITLCD_LCD_CD_GPIO_PIN 13U /*!< GPIO pin number */ +#define BOARD_INITLCD_LCD_CD_GPIO_PIN_MASK (1U << 13U) /*!< GPIO pin mask */ +#define BOARD_INITLCD_LCD_CD_PORT GPIO3 /*!< PORT peripheral base pointer */ +#define BOARD_INITLCD_LCD_CD_PIN 13U /*!< PORT pin number */ +#define BOARD_INITLCD_LCD_CD_PIN_MASK (1U << 13U) /*!< PORT pin mask */ + +/* GPIO_SD_B0_03 (coord K1), SD1_D1/J24[5]/SPI_MISO */ +/* Routed pin properties */ +#define BOARD_INITLCD_LCD_RESET_PERIPHERAL GPIO3 /*!< Peripheral name */ +#define BOARD_INITLCD_LCD_RESET_SIGNAL gpio_io /*!< Signal name */ +#define BOARD_INITLCD_LCD_RESET_CHANNEL 15U /*!< Signal channel */ + +/* Symbols to be used with GPIO driver */ +#define BOARD_INITLCD_LCD_RESET_GPIO GPIO3 /*!< GPIO peripheral base pointer */ +#define BOARD_INITLCD_LCD_RESET_GPIO_PIN 15U /*!< GPIO pin number */ +#define BOARD_INITLCD_LCD_RESET_GPIO_PIN_MASK (1U << 15U) /*!< GPIO pin mask */ +#define BOARD_INITLCD_LCD_RESET_PORT GPIO3 /*!< PORT peripheral base pointer */ +#define BOARD_INITLCD_LCD_RESET_PIN 15U /*!< PORT pin number */ +#define BOARD_INITLCD_LCD_RESET_PIN_MASK (1U << 15U) /*!< PORT pin mask */ + +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitLCD(void); + +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitKeyboard(void); /* GPIO_AD_B0_12 (coord K14), UART1_TXD */ /* Routed pin properties */ @@ -59,106 +211,6 @@ void BOARD_InitPins(void); */ void BOARD_InitDEBUG_UART(void); -#define BOARD_INITCSI_IOMUXC_GPR_GPR26_GPIO_MUX1_GPIO_SEL_MASK 0x040000U /*!< GPIO1 and GPIO6 share same IO MUX function, GPIO_MUX1 selects one GPIO function: affected bits mask */ - -/* GPIO_AD_B1_08 (coord H13), AUD_INT/CSI_D9//J35[13]/J22[4] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_D9_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_D9_SIGNAL csi_data /*!< Signal name */ -#define BOARD_INITCSI_CSI_D9_CHANNEL 9U /*!< Signal channel */ - -/* GPIO_AD_B1_09 (coord M13), SAI1_MCLK/CSI_D8/J35[11] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_D8_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_D8_SIGNAL csi_data /*!< Signal name */ -#define BOARD_INITCSI_CSI_D8_CHANNEL 8U /*!< Signal channel */ - -/* GPIO_AD_B1_10 (coord L13), SAI1_RX_SYNC/CSI_D7/J35[9]/J23[1] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_D7_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_D7_SIGNAL csi_data /*!< Signal name */ -#define BOARD_INITCSI_CSI_D7_CHANNEL 7U /*!< Signal channel */ - -/* GPIO_AD_B1_11 (coord J13), SAI1_RX_BCLK/CSI_D6/J35[7]/J23[2] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_D6_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_D6_SIGNAL csi_data /*!< Signal name */ -#define BOARD_INITCSI_CSI_D6_CHANNEL 6U /*!< Signal channel */ - -/* GPIO_AD_B1_12 (coord H12), SAI1_RXD/CSI_D5/J35[5]/U13[16] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_D5_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_D5_SIGNAL csi_data /*!< Signal name */ -#define BOARD_INITCSI_CSI_D5_CHANNEL 5U /*!< Signal channel */ - -/* GPIO_AD_B1_13 (coord H11), SAI1_TXD/CSI_D4/J35[3]/U13[14] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_D4_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_D4_SIGNAL csi_data /*!< Signal name */ -#define BOARD_INITCSI_CSI_D4_CHANNEL 4U /*!< Signal channel */ - -/* GPIO_AD_B1_15 (coord J14), SAI1_TX_SYNC/CSI_D2/J35[6]/U13[13] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_D2_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_D2_SIGNAL csi_data /*!< Signal name */ -#define BOARD_INITCSI_CSI_D2_CHANNEL 2U /*!< Signal channel */ - -/* GPIO_AD_B1_14 (coord G12), SAI1_TX_BCLK/CSI_D3/J35[4]/U13[12] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_D3_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_D3_SIGNAL csi_data /*!< Signal name */ -#define BOARD_INITCSI_CSI_D3_CHANNEL 3U /*!< Signal channel */ - -/* GPIO_AD_B1_04 (coord L12), CSI_PIXCLK/J35[8]/J23[3] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_PIXCLK_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_PIXCLK_SIGNAL csi_pixclk /*!< Signal name */ - -/* GPIO_AD_B1_05 (coord K12), CSI_MCLK/J35[12]/J23[4] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_MCLK_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_MCLK_SIGNAL csi_mclk /*!< Signal name */ - -/* GPIO_AD_B1_06 (coord J12), CSI_VSYNC/J35[18]/J22[2]/UART_TX */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_VSYNC_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_VSYNC_SIGNAL csi_vsync /*!< Signal name */ - -/* GPIO_AD_B1_07 (coord K10), CSI_HSYNC/J35[16]/J22[1]/UART_RX */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_HSYNC_PERIPHERAL CSI /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_HSYNC_SIGNAL csi_hsync /*!< Signal name */ - -/* GPIO_AD_B1_00 (coord J11), I2C1_SCL/CSI_I2C_SCL/J35[20]/J23[6]/U13[17]/U32[4] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_I2C_SCL_PERIPHERAL LPI2C1 /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_I2C_SCL_SIGNAL SCL /*!< Signal name */ - -/* GPIO_AD_B1_01 (coord K11), I2C1_SDA/CSI_I2C_SDA/J35[22]/J23[5]/U13[18]/U32[6] */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_I2C_SDA_PERIPHERAL LPI2C1 /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_I2C_SDA_SIGNAL SDA /*!< Signal name */ - -/* GPIO_AD_B1_02 (coord L11), CSI_PWDN */ -/* Routed pin properties */ -#define BOARD_INITCSI_CSI_PWDN_PERIPHERAL GPIO1 /*!< Peripheral name */ -#define BOARD_INITCSI_CSI_PWDN_SIGNAL gpio_io /*!< Signal name */ -#define BOARD_INITCSI_CSI_PWDN_CHANNEL 18U /*!< Signal channel */ - -/* Symbols to be used with GPIO driver */ -#define BOARD_INITCSI_CSI_PWDN_GPIO GPIO1 /*!< GPIO peripheral base pointer */ -#define BOARD_INITCSI_CSI_PWDN_GPIO_PIN 18U /*!< GPIO pin number */ -#define BOARD_INITCSI_CSI_PWDN_GPIO_PIN_MASK (1U << 18U) /*!< GPIO pin mask */ -#define BOARD_INITCSI_CSI_PWDN_PORT GPIO1 /*!< PORT peripheral base pointer */ -#define BOARD_INITCSI_CSI_PWDN_PIN 18U /*!< PORT pin number */ -#define BOARD_INITCSI_CSI_PWDN_PIN_MASK (1U << 18U) /*!< PORT pin mask */ - -/*! - * @brief Configures pin routing and optionally pin electrical features. - * - */ -void BOARD_InitCSI(void); - #if defined(__cplusplus) } #endif diff --git a/nxp/drivers/fsl_lpspi.c b/nxp/drivers/fsl_lpspi.c new file mode 100644 index 0000000..fd28621 --- /dev/null +++ b/nxp/drivers/fsl_lpspi.c @@ -0,0 +1,2421 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_lpspi.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.lpspi" +#endif + +/*! + * @brief Default watermark values. + * + * The default watermarks are set to zero. + */ +enum _lpspi_default_watermarks +{ + kLpspiDefaultTxWatermark = 0, + kLpspiDefaultRxWatermark = 0, +}; + +/* + * whichPcs, masterConfig->pcsActiveHighOrLow); + + /* Set Configuration Register 1 related setting.*/ + base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK | LPSPI_CFGR1_NOSTALL_MASK | + LPSPI_CFGR1_SAMPLE_MASK)) | + LPSPI_CFGR1_OUTCFG(masterConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(masterConfig->pinCfg) | + LPSPI_CFGR1_NOSTALL(0) | LPSPI_CFGR1_SAMPLE((uint32_t)masterConfig->enableInputDelay); + + /* Set baudrate and delay times*/ + (void)LPSPI_MasterSetBaudRate(base, masterConfig->baudRate, srcClock_Hz, &tcrPrescaleValue); + + /* Set default watermarks */ + LPSPI_SetFifoWatermarks(base, (uint32_t)kLpspiDefaultTxWatermark, (uint32_t)kLpspiDefaultRxWatermark); + + /* Set Transmit Command Register*/ + base->TCR = LPSPI_TCR_CPOL(masterConfig->cpol) | LPSPI_TCR_CPHA(masterConfig->cpha) | + LPSPI_TCR_LSBF(masterConfig->direction) | LPSPI_TCR_FRAMESZ(masterConfig->bitsPerFrame - 1U) | + LPSPI_TCR_PRESCALE(tcrPrescaleValue) | LPSPI_TCR_PCS(masterConfig->whichPcs); + + LPSPI_Enable(base, true); + + (void)LPSPI_MasterSetDelayTimes(base, masterConfig->pcsToSckDelayInNanoSec, kLPSPI_PcsToSck, srcClock_Hz); + (void)LPSPI_MasterSetDelayTimes(base, masterConfig->lastSckToPcsDelayInNanoSec, kLPSPI_LastSckToPcs, srcClock_Hz); + (void)LPSPI_MasterSetDelayTimes(base, masterConfig->betweenTransferDelayInNanoSec, kLPSPI_BetweenTransfer, + srcClock_Hz); + + LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA); +} + +/*! + * brief Sets the lpspi_master_config_t structure to default values. + * + * This API initializes the configuration structure for LPSPI_MasterInit(). + * The initialized structure can remain unchanged in LPSPI_MasterInit(), or can be modified + * before calling the LPSPI_MasterInit(). + * Example: + * code + * lpspi_master_config_t masterConfig; + * LPSPI_MasterGetDefaultConfig(&masterConfig); + * endcode + * param masterConfig pointer to lpspi_master_config_t structure + */ +void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig) +{ + assert(masterConfig != NULL); + + /* Initializes the configure structure to zero. */ + (void)memset(masterConfig, 0, sizeof(*masterConfig)); + + masterConfig->baudRate = 500000; + masterConfig->bitsPerFrame = 8; + masterConfig->cpol = kLPSPI_ClockPolarityActiveHigh; + masterConfig->cpha = kLPSPI_ClockPhaseFirstEdge; + masterConfig->direction = kLPSPI_MsbFirst; + + masterConfig->pcsToSckDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U; + masterConfig->lastSckToPcsDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U; + masterConfig->betweenTransferDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U; + + masterConfig->whichPcs = kLPSPI_Pcs0; + masterConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow; + + masterConfig->pinCfg = kLPSPI_SdiInSdoOut; + masterConfig->dataOutConfig = kLpspiDataOutRetained; + + masterConfig->enableInputDelay = false; +} + +/*! + * brief LPSPI slave configuration. + * + * param base LPSPI peripheral address. + * param slaveConfig Pointer to a structure lpspi_slave_config_t. + */ +void LPSPI_SlaveInit(LPSPI_Type *base, const lpspi_slave_config_t *slaveConfig) +{ + assert(slaveConfig != NULL); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPSPI_GetInstance(base); + /* Enable LPSPI clock */ + (void)CLOCK_EnableClock(s_lpspiClocks[instance]); + +#if defined(LPSPI_PERIPH_CLOCKS) + (void)CLOCK_EnableClock(s_LpspiPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + LPSPI_SetMasterSlaveMode(base, kLPSPI_Slave); + + LPSPI_SetOnePcsPolarity(base, slaveConfig->whichPcs, slaveConfig->pcsActiveHighOrLow); + + base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK)) | + LPSPI_CFGR1_OUTCFG(slaveConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(slaveConfig->pinCfg); + + LPSPI_SetFifoWatermarks(base, (uint32_t)kLpspiDefaultTxWatermark, (uint32_t)kLpspiDefaultRxWatermark); + + base->TCR = LPSPI_TCR_CPOL(slaveConfig->cpol) | LPSPI_TCR_CPHA(slaveConfig->cpha) | + LPSPI_TCR_LSBF(slaveConfig->direction) | LPSPI_TCR_FRAMESZ(slaveConfig->bitsPerFrame - 1U); + + /* This operation will set the dummy data for edma transfer, no effect in interrupt way. */ + LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA); + + LPSPI_Enable(base, true); +} + +/*! + * brief Sets the lpspi_slave_config_t structure to default values. + * + * This API initializes the configuration structure for LPSPI_SlaveInit(). + * The initialized structure can remain unchanged in LPSPI_SlaveInit() or can be modified + * before calling the LPSPI_SlaveInit(). + * Example: + * code + * lpspi_slave_config_t slaveConfig; + * LPSPI_SlaveGetDefaultConfig(&slaveConfig); + * endcode + * param slaveConfig pointer to lpspi_slave_config_t structure. + */ +void LPSPI_SlaveGetDefaultConfig(lpspi_slave_config_t *slaveConfig) +{ + assert(slaveConfig != NULL); + + /* Initializes the configure structure to zero. */ + (void)memset(slaveConfig, 0, sizeof(*slaveConfig)); + + slaveConfig->bitsPerFrame = 8; /*!< Bits per frame, minimum 8, maximum 4096.*/ + slaveConfig->cpol = kLPSPI_ClockPolarityActiveHigh; /*!< Clock polarity. */ + slaveConfig->cpha = kLPSPI_ClockPhaseFirstEdge; /*!< Clock phase. */ + slaveConfig->direction = kLPSPI_MsbFirst; /*!< MSB or LSB data shift direction. */ + + slaveConfig->whichPcs = kLPSPI_Pcs0; /*!< Desired Peripheral Chip Select (pcs) */ + slaveConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow; /*!< Desired PCS active high or low */ + + slaveConfig->pinCfg = kLPSPI_SdiInSdoOut; + slaveConfig->dataOutConfig = kLpspiDataOutRetained; +} + +/*! + * brief Restores the LPSPI peripheral to reset state. Note that this function + * sets all registers to reset state. As a result, the LPSPI module can't work after calling + * this API. + * param base LPSPI peripheral address. + */ +void LPSPI_Reset(LPSPI_Type *base) +{ + /* Reset all internal logic and registers, except the Control Register. Remains set until cleared by software.*/ + base->CR |= LPSPI_CR_RST_MASK; + + /* Software reset doesn't reset the CR, so manual reset the FIFOs */ + base->CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK; + + /* Master logic is not reset and module is disabled.*/ + base->CR = 0x00U; +} + +/*! + * brief De-initializes the LPSPI peripheral. Call this API to disable the LPSPI clock. + * param base LPSPI peripheral address. + */ +void LPSPI_Deinit(LPSPI_Type *base) +{ + /* Reset to default value */ + LPSPI_Reset(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPSPI_GetInstance(base); + /* Enable LPSPI clock */ + (void)CLOCK_DisableClock(s_lpspiClocks[instance]); + +#if defined(LPSPI_PERIPH_CLOCKS) + (void)CLOCK_DisableClock(s_LpspiPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base, + lpspi_which_pcs_t pcs, + lpspi_pcs_polarity_config_t activeLowOrHigh) +{ + uint32_t cfgr1Value = 0; + /* Clear the PCS polarity bit */ + cfgr1Value = base->CFGR1 & ~(1UL << (LPSPI_CFGR1_PCSPOL_SHIFT + (uint32_t)pcs)); + + /* Configure the PCS polarity bit according to the activeLowOrHigh setting */ + base->CFGR1 = cfgr1Value | ((uint32_t)activeLowOrHigh << (LPSPI_CFGR1_PCSPOL_SHIFT + (uint32_t)pcs)); +} + +/*! + * brief Sets the LPSPI baud rate in bits per second. + * + * This function takes in the desired bitsPerSec (baud rate) and calculates the nearest + * possible baud rate without exceeding the desired baud rate and returns the + * calculated baud rate in bits-per-second. It requires the caller to provide + * the frequency of the module source clock (in Hertz). Note that the baud rate + * does not go into effect until the Transmit Control Register (TCR) is programmed + * with the prescale value. Hence, this function returns the prescale tcrPrescaleValue + * parameter for later programming in the TCR. The higher level + * peripheral driver should alert the user of an out of range baud rate input. + * + * Note that the LPSPI module must first be disabled before configuring this. + * Note that the LPSPI module must be configured for master mode before configuring this. + * + * param base LPSPI peripheral address. + * param baudRate_Bps The desired baud rate in bits per second. + * param srcClock_Hz Module source input clock in Hertz. + * param tcrPrescaleValue The TCR prescale value needed to program the TCR. + * return The actual calculated baud rate. This function may also return a "0" if the + * LPSPI is not configured for master mode or if the LPSPI module is not disabled. + */ + +uint32_t LPSPI_MasterSetBaudRate(LPSPI_Type *base, + uint32_t baudRate_Bps, + uint32_t srcClock_Hz, + uint32_t *tcrPrescaleValue) +{ + assert(tcrPrescaleValue != NULL); + + /* For master mode configuration only, if slave mode detected, return 0. + * Also, the LPSPI module needs to be disabled first, if enabled, return 0 + */ + if ((!LPSPI_IsMaster(base)) || ((base->CR & LPSPI_CR_MEN_MASK) != 0U)) + { + return 0U; + } + + uint32_t prescaler, bestPrescaler; + uint32_t scaler, bestScaler; + uint32_t realBaudrate, bestBaudrate; + uint32_t diff, min_diff; + uint32_t desiredBaudrate = baudRate_Bps; + + /* find combination of prescaler and scaler resulting in baudrate closest to the + * requested value + */ + min_diff = 0xFFFFFFFFU; + + /* Set to maximum divisor value bit settings so that if baud rate passed in is less + * than the minimum possible baud rate, then the SPI will be configured to the lowest + * possible baud rate + */ + bestPrescaler = 7; + bestScaler = 255; + + bestBaudrate = 0; /* required to avoid compilation warning */ + + /* In all for loops, if min_diff = 0, the exit for loop*/ + for (prescaler = 0U; prescaler < 8U; prescaler++) + { + if (min_diff == 0U) + { + break; + } + for (scaler = 0U; scaler < 256U; scaler++) + { + if (min_diff == 0U) + { + break; + } + realBaudrate = (srcClock_Hz / (s_baudratePrescaler[prescaler] * (scaler + 2U))); + + /* calculate the baud rate difference based on the conditional statement + * that states that the calculated baud rate must not exceed the desired baud rate + */ + if (desiredBaudrate >= realBaudrate) + { + diff = desiredBaudrate - realBaudrate; + if (min_diff > diff) + { + /* a better match found */ + min_diff = diff; + bestPrescaler = prescaler; + bestScaler = scaler; + bestBaudrate = realBaudrate; + } + } + } + } + + /* Write the best baud rate scalar to the CCR. + * Note, no need to check for error since we've already checked to make sure the module is + * disabled and in master mode. Also, there is a limit on the maximum divider so we will not + * exceed this. + */ +#if defined(FSL_FEATURE_LPSPI_HAS_CCR1) && FSL_FEATURE_LPSPI_HAS_CCR1 + /* When CCR1 is present, the CCR[DBT] and CCR[SCKDIV] is write only, all read will return 0 + The real DBT and SCKDIV can be obtained in CCR1, CCR[DBT]=CCR1[SCKSCK] and CCR[SCKDIV]=CCR1[SCKHLD]+CCR1[SCKSET] + So when changing either CCR[DBT] or CCR[SCKDIV] make sure the other value is not overwritten by 0 */ + base->CCR = base->CCR | LPSPI_CCR_DBT((base->CCR1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT) | + LPSPI_CCR_SCKDIV(bestScaler); +#else + base->CCR = (base->CCR & ~LPSPI_CCR_SCKDIV_MASK) | LPSPI_CCR_SCKDIV(bestScaler); +#endif /* FSL_FEATURE_LPSPI_HAS_CCR1 */ + + /* return the best prescaler value for user to use later */ + *tcrPrescaleValue = bestPrescaler; + + /* return the actual calculated baud rate */ + return bestBaudrate; +} + +/*! + * brief Manually configures a specific LPSPI delay parameter (module must be disabled to + * change the delay values). + * + * This function configures the following: + * SCK to PCS delay, or + * PCS to SCK delay, or + * The configurations must occur between the transfer delay. + * + * The delay names are available in type lpspi_delay_type_t. + * + * The user passes the desired delay along with the delay value. + * This allows the user to directly set the delay values if they have + * pre-calculated them or if they simply wish to manually increment the value. + * + * Note that the LPSPI module must first be disabled before configuring this. + * Note that the LPSPI module must be configured for master mode before configuring this. + * + * param base LPSPI peripheral address. + * param scaler The 8-bit delay value 0x00 to 0xFF (255). + * param whichDelay The desired delay to configure, must be of type lpspi_delay_type_t. + */ +void LPSPI_MasterSetDelayScaler(LPSPI_Type *base, uint32_t scaler, lpspi_delay_type_t whichDelay) +{ + /*These settings are only relevant in master mode */ +#if defined(FSL_FEATURE_LPSPI_HAS_CCR1) && FSL_FEATURE_LPSPI_HAS_CCR1 + /* When CCR1 is present, the CCR[DBT] and CCR[SCKDIV] is write only, all read will return 0 + The real DBT and SCKDIV can be obtained in CCR1, CCR[DBT]=CCR1[SCKSCK] and CCR[SCKDIV]=CCR1[SCKHLD]+CCR1[SCKSET] + So when changing either CCR[DBT] or CCR[SCKDIV] make sure the other value is not overwritten by 0 */ + uint32_t dbt = (base->CCR1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT; + uint32_t sckdiv = (base->CCR1 & LPSPI_CCR1_SCKHLD_MASK) >> LPSPI_CCR1_SCKHLD_SHIFT; + sckdiv += (base->CCR1 & LPSPI_CCR1_SCKSET_MASK) >> LPSPI_CCR1_SCKSET_SHIFT; + switch (whichDelay) + { + case kLPSPI_PcsToSck: + base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler) | LPSPI_CCR_DBT(dbt) | + LPSPI_CCR_SCKDIV(sckdiv); + + break; + case kLPSPI_LastSckToPcs: + base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler) | LPSPI_CCR_DBT(dbt) | + LPSPI_CCR_SCKDIV(sckdiv); + + break; + case kLPSPI_BetweenTransfer: + base->CCR = base->CCR | LPSPI_CCR_DBT(scaler) | LPSPI_CCR_SCKDIV(sckdiv); +#else + switch (whichDelay) + { + case kLPSPI_PcsToSck: + base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler); + + break; + case kLPSPI_LastSckToPcs: + base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler); + + break; + case kLPSPI_BetweenTransfer: + base->CCR = (base->CCR & (~LPSPI_CCR_DBT_MASK)) | LPSPI_CCR_DBT(scaler); +#endif /* FSL_FEATURE_LPSPI_HAS_CCR1 */ + break; + default: + assert(false); + break; + } +} + +/*! + * brief Calculates the delay based on the desired delay input in nanoseconds (module must be + * disabled to change the delay values). + * + * This function calculates the values for the following: + * SCK to PCS delay, or + * PCS to SCK delay, or + * The configurations must occur between the transfer delay. + * + * The delay names are available in type lpspi_delay_type_t. + * + * The user passes the desired delay and the desired delay value in + * nano-seconds. The function calculates the value needed for the desired delay parameter + * and returns the actual calculated delay because an exact delay match may not be possible. In this + * case, the closest match is calculated without going below the desired delay value input. + * It is possible to input a very large delay value that exceeds the capability of the part, in + * which case the maximum supported delay is returned. It is up to the higher level + * peripheral driver to alert the user of an out of range delay input. + * + * Note that the LPSPI module must be configured for master mode before configuring this. And note that + * the delayTime = LPSPI_clockSource / (PRESCALE * Delay_scaler). + * + * param base LPSPI peripheral address. + * param delayTimeInNanoSec The desired delay value in nano-seconds. + * param whichDelay The desired delay to configuration, which must be of type lpspi_delay_type_t. + * param srcClock_Hz Module source input clock in Hertz. + * return actual Calculated delay value in nano-seconds. + */ +uint32_t LPSPI_MasterSetDelayTimes(LPSPI_Type *base, + uint32_t delayTimeInNanoSec, + lpspi_delay_type_t whichDelay, + uint32_t srcClock_Hz) +{ + uint64_t realDelay, bestDelay; + uint32_t scaler, bestScaler; + uint32_t diff, min_diff; + uint64_t initialDelayNanoSec; + uint32_t clockDividedPrescaler; + + /* For delay between transfer, an additional scaler value is needed */ + uint32_t additionalScaler = 0; + + /*As the RM note, the LPSPI baud rate clock is itself divided by the PRESCALE setting, which can vary between + * transfers.*/ + clockDividedPrescaler = + srcClock_Hz / s_baudratePrescaler[(base->TCR & LPSPI_TCR_PRESCALE_MASK) >> LPSPI_TCR_PRESCALE_SHIFT]; + + /* Find combination of prescaler and scaler resulting in the delay closest to the requested value.*/ + min_diff = 0xFFFFFFFFU; + + /* Initialize scaler to max value to generate the max delay */ + bestScaler = 0xFFU; + + /* Calculate the initial (min) delay and maximum possible delay based on the specific delay as + * the delay divisors are slightly different based on which delay we are configuring. + */ + if (whichDelay == kLPSPI_BetweenTransfer) + { + /* First calculate the initial, default delay, note min delay is 2 clock cycles. Due to large size of + calculated values (uint64_t), we need to break up the calculation into several steps to ensure + accurate calculated results + */ + initialDelayNanoSec = 1000000000U; + initialDelayNanoSec *= 2U; + initialDelayNanoSec /= clockDividedPrescaler; + + /* Calculate the maximum delay */ + bestDelay = 1000000000U; + bestDelay *= 257U; /* based on DBT+2, or 255 + 2 */ + bestDelay /= clockDividedPrescaler; + + additionalScaler = 1U; + } + else + { + /* First calculate the initial, default delay, min delay is 1 clock cycle. Due to large size of calculated + values (uint64_t), we need to break up the calculation into several steps to ensure accurate calculated + results. + */ + initialDelayNanoSec = 1000000000U; + initialDelayNanoSec /= clockDividedPrescaler; + + /* Calculate the maximum delay */ + bestDelay = 1000000000U; + bestDelay *= 256U; /* based on SCKPCS+1 or PCSSCK+1, or 255 + 1 */ + bestDelay /= clockDividedPrescaler; + + additionalScaler = 0U; + } + + /* If the initial, default delay is already greater than the desired delay, then + * set the delay to their initial value (0) and return the delay. In other words, + * there is no way to decrease the delay value further. + */ + if (initialDelayNanoSec >= delayTimeInNanoSec) + { + LPSPI_MasterSetDelayScaler(base, 0, whichDelay); + return (uint32_t)initialDelayNanoSec; + } + + /* If min_diff = 0, the exit for loop */ + for (scaler = 0U; scaler < 256U; scaler++) + { + if (min_diff == 0U) + { + break; + } + /* Calculate the real delay value as we cycle through the scaler values. + Due to large size of calculated values (uint64_t), we need to break up the + calculation into several steps to ensure accurate calculated results + */ + realDelay = 1000000000U; + realDelay *= ((uint64_t)scaler + 1UL + (uint64_t)additionalScaler); + realDelay /= clockDividedPrescaler; + + /* calculate the delay difference based on the conditional statement + * that states that the calculated delay must not be less then the desired delay + */ + if (realDelay >= delayTimeInNanoSec) + { + diff = (uint32_t)(realDelay - (uint64_t)delayTimeInNanoSec); + if (min_diff > diff) + { + /* a better match found */ + min_diff = diff; + bestScaler = scaler; + bestDelay = realDelay; + } + } + } + + /* write the best scaler value for the delay */ + LPSPI_MasterSetDelayScaler(base, bestScaler, whichDelay); + + /* return the actual calculated delay value (in ns) */ + return (uint32_t)bestDelay; +} + +/*Transactional APIs -- Master*/ + +/*! + * brief Initializes the LPSPI master handle. + * + * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a + * specified LPSPI instance, call this API once to get the initialized handle. + + * param base LPSPI peripheral address. + * param handle LPSPI handle pointer to lpspi_master_handle_t. + * param callback DSPI callback. + * param userData callback function parameter. + */ +void LPSPI_MasterTransferCreateHandle(LPSPI_Type *base, + lpspi_master_handle_t *handle, + lpspi_master_transfer_callback_t callback, + void *userData) +{ + assert(handle != NULL); + + /* Zero the handle. */ + (void)memset(handle, 0, sizeof(*handle)); + + s_lpspiHandle[LPSPI_GetInstance(base)] = handle; + + /* Set irq handler. */ + s_lpspiMasterIsr = LPSPI_MasterTransferHandleIRQ; + + handle->callback = callback; + handle->userData = userData; +} + +/*! + * brief Check the argument for transfer . + * + * param base LPSPI peripheral address. + * param transfer the transfer struct to be used. + * param isEdma True to check for EDMA transfer, false to check interrupt non-blocking transfer + * return Return true for right and false for wrong. + */ +bool LPSPI_CheckTransferArgument(LPSPI_Type *base, lpspi_transfer_t *transfer, bool isEdma) +{ + assert(transfer != NULL); + uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U; + uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U; + uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK); + /* If the transfer count is zero, then return immediately.*/ + if (transfer->dataSize == 0U) + { + return false; + } + + /* If both send buffer and receive buffer is null */ + if ((NULL == (transfer->txData)) && (NULL == (transfer->rxData))) + { + return false; + } + + /*The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4 . + *For bytesPerFrame greater than 4 situation: + *the transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4 , + *otherwise , the transfer data size can be integer multiples of bytesPerFrame. + */ + if (bytesPerFrame <= 4U) + { + if ((transfer->dataSize % bytesPerFrame) != 0U) + { + return false; + } + } + else + { + if ((bytesPerFrame % 4U) != 0U) + { + if (transfer->dataSize != bytesPerFrame) + { + return false; + } + } + else + { + if ((transfer->dataSize % bytesPerFrame) != 0U) + { + return false; + } + } + } + + /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */ + if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) + { + /* The 3-wire mode can't send and receive data at the same time. */ + if ((transfer->txData != NULL) && (transfer->rxData != NULL)) + { + return false; + } + if (NULL == transfer->txData) + { + base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK; + } + } + + if (isEdma && ((bytesPerFrame % 4U) == 3U)) + { + return false; + } + + return true; +} + +static bool LPSPI_MasterTransferWriteAllTxData(LPSPI_Type *base, + lpspi_transfer_t *transfer, + lpspi_transfer_blocking_param_t *stateParams) +{ + uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)]; + uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; + uint32_t txRemainingByteCount = transfer->dataSize; + bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U); + uint32_t wordToSend = + ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24); + uint32_t rxFifoMaxBytes = MIN(bytesPerFrame, 4U) * LPSPI_GetRxFifoSize(base); + uint32_t readData; + /*Write the TX data until txRemainingByteCount is equal to 0 */ + while (txRemainingByteCount > 0U) + { + if (txRemainingByteCount < (stateParams->bytesEachWrite)) + { + (stateParams->bytesEachWrite) = (uint8_t)txRemainingByteCount; + } + + /*Wait until TX FIFO is not full*/ +#if SPI_RETRY_TIMES + uint32_t waitTimes = SPI_RETRY_TIMES; + while ((LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base)) && (--waitTimes) != 0U)) +#else + while (LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base)) +#endif + { + } +#if SPI_RETRY_TIMES + if (waitTimes == 0U) + { + return false; + } +#endif + + /* To prevent rxfifo overflow, ensure transmitting and receiving are executed in parallel */ + if (((NULL == (transfer->rxData)) || + ((stateParams->rxRemainingByteCount) - txRemainingByteCount) < rxFifoMaxBytes)) + { + if (stateParams->isTxMask) + { + /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared + by hardware every time when TCR[FRAMESZ] bit of data is transfered. + In this case TCR[TXMSK] should be set to initiate each transfer. */ + base->TCR |= LPSPI_TCR_TXMSK_MASK; + if (stateParams->isPcsContinuous && (txRemainingByteCount == bytesPerFrame)) + { + /* For the last piece of frame size of data, if is PCS continous mode(TCR[CONT]), TCR[CONTC] should + * be cleared to de-assert the PCS. Be sure to clear the TXMSK as well otherwise another FRAMESZ + * of data will be received. */ + base->TCR &= ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK | LPSPI_TCR_TXMSK_MASK); + } + txRemainingByteCount -= bytesPerFrame; + } + else + { + if ((transfer->txData) != NULL) + { + wordToSend = LPSPI_CombineWriteData((transfer->txData), (stateParams->bytesEachWrite), isByteSwap); + (transfer->txData) += (stateParams->bytesEachWrite); + } + /* Otherwise push data to tx FIFO to initiate transfer */ + LPSPI_WriteData(base, wordToSend); + txRemainingByteCount -= (stateParams->bytesEachWrite); + } + } + + /* Check whether there is RX data in RX FIFO . Read out the RX data so that the RX FIFO would not overrun. */ + if (((transfer->rxData) != NULL) && ((stateParams->rxRemainingByteCount) != 0U)) + { + /* To ensure parallel execution in 3-wire mode, after writting 1 to TXMSK to generate clock of + bytesPerFrame's data wait until bytesPerFrame's data is received. */ + while ((stateParams->isTxMask) && (LPSPI_GetRxFifoCount(base) == 0U)) + { + } +#if SPI_RETRY_TIMES + uint32_t waitTimes = SPI_RETRY_TIMES; + while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U)) +#else + while (LPSPI_GetRxFifoCount(base) != 0U) +#endif + { + readData = LPSPI_ReadData(base); + if ((stateParams->rxRemainingByteCount) < (stateParams->bytesEachRead)) + { + (stateParams->bytesEachRead) = (uint8_t)(stateParams->rxRemainingByteCount); + } + + LPSPI_SeparateReadData((transfer->rxData), readData, (stateParams->bytesEachRead), isByteSwap); + (transfer->rxData) += (stateParams->bytesEachRead); + + (stateParams->rxRemainingByteCount) -= (stateParams->bytesEachRead); + } +#if SPI_RETRY_TIMES + if (waitTimes == 0U) + { + return false; + } +#endif + } + } + return true; +} + +static bool LPSPI_MasterTransferClearTCR(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams) +{ +#if SPI_RETRY_TIMES + uint32_t waitTimes = SPI_RETRY_TIMES; + while ((LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base)) && (--waitTimes != 0U)) +#else + while (LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base)) +#endif + { + } +#if SPI_RETRY_TIMES + if (waitTimes == 0U) + { + return false; + } +#endif + base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK)); + return true; +} + +static bool LPSPI_MasterTransferReadDataInFifo(LPSPI_Type *base, + lpspi_transfer_t *transfer, + lpspi_transfer_blocking_param_t *stateParams) +{ + uint32_t readData; + bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U); + while ((stateParams->rxRemainingByteCount) > 0U) + { +#if SPI_RETRY_TIMES + uint32_t waitTimes = SPI_RETRY_TIMES; + while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U)) +#else + while (LPSPI_GetRxFifoCount(base) != 0U) +#endif + { + readData = LPSPI_ReadData(base); + + if ((stateParams->rxRemainingByteCount) < (stateParams->bytesEachRead)) + { + (stateParams->bytesEachRead) = (uint8_t)(stateParams->rxRemainingByteCount); + } + + LPSPI_SeparateReadData((transfer->rxData), readData, (stateParams->bytesEachRead), isByteSwap); + (transfer->rxData) += (stateParams->bytesEachRead); + + (stateParams->rxRemainingByteCount) -= (stateParams->bytesEachRead); + } +#if SPI_RETRY_TIMES + if (waitTimes == 0U) + { + return false; + } +#endif + } + return true; +} + +static bool LPSPI_MasterTransferReadDataInFifoNoBuf(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams) +{ +#if SPI_RETRY_TIMES + uint32_t waitTimes = SPI_RETRY_TIMES; + while (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U) && (--waitTimes != 0U)) +#else + while ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U) +#endif + { + } +#if SPI_RETRY_TIMES + if (waitTimes == 0U) + { + return false; + } +#endif + return true; +} + +/*! + * brief LPSPI master transfer data using a polling method. + * + * This function transfers data using a polling method. This is a blocking function, which does not return until all + * transfers have been completed. + * + * Note: + * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. + * For bytesPerFrame greater than 4: + * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4. + * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. + * + * param base LPSPI peripheral address. + * param transfer pointer to lpspi_transfer_t structure. + * return status of status_t. + */ +status_t LPSPI_MasterTransferBlocking(LPSPI_Type *base, lpspi_transfer_t *transfer) +{ + assert(transfer != NULL); + + /* Check that LPSPI is not busy.*/ + if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ModuleBusyFlag) != 0U) + { + return kStatus_LPSPI_Busy; + } + LPSPI_Enable(base, false); + /* Check arguements */ + if (!LPSPI_CheckTransferArgument(base, transfer, false)) + { + return kStatus_InvalidArgument; + } + + LPSPI_FlushFifo(base, true, true); + LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag); + + /* Variables */ + uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT; + uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK); + lpspi_transfer_blocking_param_t stateParams; + (void)memset(&stateParams, 0, sizeof(stateParams)); + + stateParams.isTxMask = false; + stateParams.rxRemainingByteCount = transfer->dataSize; + /*The TX and RX FIFO sizes are always the same*/ + uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; + /* No need to configure PCS continous if the transfer byte count is smaller than frame size */ + stateParams.isPcsContinuous = (((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U) && + (bytesPerFrame < transfer->dataSize)); + + /* Mask tx data in half duplex mode */ + if (((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) && + (transfer->txData == NULL)) + { + stateParams.isTxMask = true; + } + + base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); + LPSPI_Enable(base, true); + + /* Configure transfer control register. */ + base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | + LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) | + LPSPI_TCR_PCS(whichPcs); + + /*TCR is also shared the FIFO, so wait for TCR written.*/ + if (!LPSPI_TxFifoReady(base)) + { + return kStatus_LPSPI_Timeout; + } + + /* PCS should be configured separately from the other bits, otherwise it will not take effect. */ + base->TCR |= LPSPI_TCR_CONT(stateParams.isPcsContinuous) | LPSPI_TCR_CONTC(stateParams.isPcsContinuous) | + LPSPI_TCR_RXMSK(NULL == transfer->rxData); + + /*TCR is also shared the FIFO, so wait for TCR written.*/ + if (!LPSPI_TxFifoReady(base)) + { + return kStatus_LPSPI_Timeout; + } + + if (bytesPerFrame <= 4U) + { + stateParams.bytesEachWrite = (uint8_t)bytesPerFrame; + stateParams.bytesEachRead = (uint8_t)bytesPerFrame; + } + else + { + stateParams.bytesEachWrite = 4U; + stateParams.bytesEachRead = 4U; + } + + if (false == LPSPI_MasterTransferWriteAllTxData(base, transfer, &stateParams)) + { + return kStatus_LPSPI_Timeout; + } + + if (stateParams.isPcsContinuous && !stateParams.isTxMask) + { + /* In PCS continous mode(TCR[CONT]), after write all the data in TX FIFO, TCR[CONTC] and TCR[CONT] should be + cleared to de-assert the PCS. Note that TCR register also use the TX FIFO. Also CONTC should be cleared when + tx is not masked, otherwise written to TCR register with TXMSK bit wet will initiate a new transfer. */ + if (false == LPSPI_MasterTransferClearTCR(base, &stateParams)) + { + return kStatus_LPSPI_Timeout; + } + } + + /*Read out the RX data in FIFO*/ + if (transfer->rxData != NULL) + { + if (false == LPSPI_MasterTransferReadDataInFifo(base, transfer, &stateParams)) + { + return kStatus_LPSPI_Timeout; + } + } + else + { + /* If no RX buffer, then transfer is not complete until transfer complete flag sets */ + if (false == LPSPI_MasterTransferReadDataInFifoNoBuf(base, &stateParams)) + { + return kStatus_LPSPI_Timeout; + } + } + + return kStatus_Success; +} + +/*! + * brief LPSPI master transfer data using an interrupt method. + * + * This function transfers data using an interrupt method. This is a non-blocking function, which returns right away. + * When all data is transferred, the callback function is called. + * + * Note: + * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. + * For bytesPerFrame greater than 4: + * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4. + * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. + * + * param base LPSPI peripheral address. + * param handle pointer to lpspi_master_handle_t structure which stores the transfer state. + * param transfer pointer to lpspi_transfer_t structure. + * return status of status_t. + */ +status_t LPSPI_MasterTransferNonBlocking(LPSPI_Type *base, lpspi_master_handle_t *handle, lpspi_transfer_t *transfer) +{ + assert(handle != NULL); + assert(transfer != NULL); + + /* Check that we're not busy.*/ + if (handle->state == (uint8_t)kLPSPI_Busy) + { + return kStatus_LPSPI_Busy; + } + + LPSPI_Enable(base, false); + /* Check arguements */ + if (!LPSPI_CheckTransferArgument(base, transfer, false)) + { + return kStatus_InvalidArgument; + } + + /* Flush FIFO, clear status, disable all the interrupts. */ + LPSPI_FlushFifo(base, true, true); + LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag); + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); + + /* Variables */ + bool isRxMask = false; + uint8_t txWatermark; + uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)]; + uint32_t tmpTimes; + uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT; + uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK); + + /* Assign the original value for members of transfer handle. */ + handle->state = (uint8_t)kLPSPI_Busy; + handle->txData = transfer->txData; + handle->rxData = transfer->rxData; + handle->txRemainingByteCount = transfer->dataSize; + handle->rxRemainingByteCount = transfer->dataSize; + handle->totalByteCount = transfer->dataSize; + handle->writeTcrInIsr = false; + handle->bytesPerFrame = (uint16_t)((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; + /* No need to configure PCS continous if the transfer byte count is smaller than frame size */ + bool isPcsContinuous = (((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U) && + (transfer->dataSize > handle->bytesPerFrame)); + handle->writeRegRemainingTimes = + (transfer->dataSize / (uint32_t)handle->bytesPerFrame) * (((uint32_t)handle->bytesPerFrame + 3U) / 4U); + handle->readRegRemainingTimes = handle->writeRegRemainingTimes; + handle->txBuffIfNull = + ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24); + /*The TX and RX FIFO sizes are always the same*/ + handle->fifoSize = LPSPI_GetRxFifoSize(base); + handle->isPcsContinuous = isPcsContinuous; + handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U); + /*Calculate the bytes for write/read the TX/RX register each time*/ + if (handle->bytesPerFrame <= 4U) + { + handle->bytesEachWrite = (uint8_t)handle->bytesPerFrame; + handle->bytesEachRead = (uint8_t)handle->bytesPerFrame; + } + else + { + handle->bytesEachWrite = 4U; + handle->bytesEachRead = 4U; + } + + /*Set the RX and TX watermarks to reduce the ISR times.*/ + if (handle->fifoSize > 1U) + { + txWatermark = 1U; + handle->rxWatermark = handle->fifoSize - 2U; + } + else + { + txWatermark = 0U; + handle->rxWatermark = 0U; + } + LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark); + + /* If there is no rxData, mask the receive data so that receive data is not stored in receive FIFO. */ + if (handle->rxData == NULL) + { + isRxMask = true; + handle->rxRemainingByteCount = 0; + } + + /* Mask tx data in half duplex mode since the tx/rx share the same pin, so that the data received from slave is not + * interfered. */ + if (((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) && + (handle->txData == NULL)) + { + handle->isTxMask = true; + } + + /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */ + base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); + + /* Enable module for following configuration of TCR to take effect. */ + LPSPI_Enable(base, true); + + /* Configure transfer control register. */ + base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | + LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) | + LPSPI_TCR_PCS(whichPcs); + + /*TCR is also shared the FIFO , so wait for TCR written.*/ + if (!LPSPI_TxFifoReady(base)) + { + return kStatus_LPSPI_Timeout; + } + + /* PCS should be configured separately from the other bits, otherwise it will not take effect. */ + base->TCR |= LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(isPcsContinuous) | LPSPI_TCR_RXMSK(isRxMask); + + /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX , + * and you should also enable the INTMUX interupt in your application. + */ + (void)EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]); + + /*TCR is also shared the FIFO , so wait for TCR written.*/ + if (!LPSPI_TxFifoReady(base)) + { + return kStatus_LPSPI_Timeout; + } + + if (handle->isTxMask) + { + /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared by + hardware every time when TCR[FRAMESZ] bit of data is transfered. In this case TCR[TXMSK] should be set to + initiate each transfer. */ + + base->TCR |= LPSPI_TCR_TXMSK_MASK; + handle->txRemainingByteCount -= (uint32_t)handle->bytesPerFrame; + } + else + { + /* Fill up the TX data in FIFO to initiate transfer */ + LPSPI_MasterTransferFillUpTxFifo(base, handle); + } + + /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data. + * The IRQ handler will get the status of RX and TX interrupt flags. + */ + if (handle->rxData != NULL) + { + if (handle->isTxMask) + { + /* if tx data is masked, transfer is initiated by writing 1 to TCR[TXMSK] and TCR[FRMESZ] bits of data is + read. If rx water mark is set larger than TCR[FRMESZ], rx interrupt will not be generated. Lower the rx + water mark setting */ + if ((handle->bytesPerFrame / 4U) < (uint16_t)handle->rxWatermark) + { + handle->rxWatermark = + (uint8_t)(handle->bytesPerFrame / 4U) > 0U ? (uint8_t)(handle->bytesPerFrame / 4U - 1U) : 0U; + base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(handle->rxWatermark); + } + } + else + { + /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise + *there is not RX interrupt for the last datas because the RX count is not greater than rxWatermark. + */ + tmpTimes = handle->readRegRemainingTimes; + if (tmpTimes <= handle->rxWatermark) + { + base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(tmpTimes - 1U); + } + } + + LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable); + } + else + { + LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable); + } + + return kStatus_Success; +} + +static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle) +{ + assert(handle != NULL); + + uint32_t wordToSend = 0; + uint8_t fifoSize = handle->fifoSize; + uint32_t writeRegRemainingTimes = handle->writeRegRemainingTimes; + uint32_t readRegRemainingTimes = handle->readRegRemainingTimes; + size_t txRemainingByteCount = handle->txRemainingByteCount; + uint8_t bytesEachWrite = handle->bytesEachWrite; + bool isByteSwap = handle->isByteSwap; + + /* Make sure the difference in remaining TX and RX byte counts does not exceed FIFO depth + * and that the number of TX FIFO entries does not exceed the FIFO depth. + * But no need to make the protection if there is no rxData. + */ + while ((LPSPI_GetTxFifoCount(base) < fifoSize) && + (((readRegRemainingTimes - writeRegRemainingTimes) < (uint32_t)fifoSize) || (handle->rxData == NULL))) + { + if (txRemainingByteCount < (size_t)bytesEachWrite) + { + handle->bytesEachWrite = (uint8_t)txRemainingByteCount; + bytesEachWrite = handle->bytesEachWrite; + } + + if (handle->txData != NULL) + { + wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap); + handle->txData += bytesEachWrite; + } + else + { + wordToSend = handle->txBuffIfNull; + } + + /*Write the word to TX register*/ + LPSPI_WriteData(base, wordToSend); + + /*Decrease the write TX register times.*/ + --handle->writeRegRemainingTimes; + writeRegRemainingTimes = handle->writeRegRemainingTimes; + + /*Decrease the remaining TX byte count.*/ + handle->txRemainingByteCount -= (size_t)bytesEachWrite; + txRemainingByteCount = handle->txRemainingByteCount; + + if (handle->txRemainingByteCount == 0U) + { + /* If PCS is continuous, update TCR to de-assert PCS */ + if (handle->isPcsContinuous) + { + /* Only write to the TCR if the FIFO has room */ + if (LPSPI_GetTxFifoCount(base) < fifoSize) + { + base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK)); + handle->writeTcrInIsr = false; + } + /* Else, set a global flag to tell the ISR to do write to the TCR */ + else + { + handle->writeTcrInIsr = true; + } + } + break; + } + } +} + +static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle) +{ + assert(handle != NULL); + + /* Disable interrupt requests*/ + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); + + handle->state = (uint8_t)kLPSPI_Idle; + + if (handle->callback != NULL) + { + handle->callback(base, handle, kStatus_Success, handle->userData); + } +} + +/*! + * brief Gets the master transfer remaining bytes. + * + * This function gets the master transfer remaining bytes. + * + * param base LPSPI peripheral address. + * param handle pointer to lpspi_master_handle_t structure which stores the transfer state. + * param count Number of bytes transferred so far by the non-blocking transaction. + * return status of status_t. + */ +status_t LPSPI_MasterTransferGetCount(LPSPI_Type *base, lpspi_master_handle_t *handle, size_t *count) +{ + assert(handle != NULL); + + if (NULL == count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (handle->state != (uint8_t)kLPSPI_Busy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + size_t remainingByte; + + if (handle->rxData != NULL) + { + remainingByte = handle->rxRemainingByteCount; + } + else + { + remainingByte = handle->txRemainingByteCount; + } + + *count = handle->totalByteCount - remainingByte; + + return kStatus_Success; +} + +/*! + * brief LPSPI master abort transfer which uses an interrupt method. + * + * This function aborts a transfer which uses an interrupt method. + * + * param base LPSPI peripheral address. + * param handle pointer to lpspi_master_handle_t structure which stores the transfer state. + */ +void LPSPI_MasterTransferAbort(LPSPI_Type *base, lpspi_master_handle_t *handle) +{ + assert(handle != NULL); + + /* Disable interrupt requests*/ + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); + + LPSPI_Reset(base); + + handle->state = (uint8_t)kLPSPI_Idle; + handle->txRemainingByteCount = 0; + handle->rxRemainingByteCount = 0; +} + +/*! + * brief LPSPI Master IRQ handler function. + * + * This function processes the LPSPI transmit and receive IRQ. + * + * param base LPSPI peripheral address. + * param handle pointer to lpspi_master_handle_t structure which stores the transfer state. + */ +void LPSPI_MasterTransferHandleIRQ(LPSPI_Type *base, lpspi_master_handle_t *handle) +{ + assert(handle != NULL); + + uint32_t readData; + uint8_t bytesEachRead = handle->bytesEachRead; + bool isByteSwap = handle->isByteSwap; + uint32_t readRegRemainingTimes = handle->readRegRemainingTimes; + + if (handle->rxData != NULL) + { + if (handle->rxRemainingByteCount != 0U) + { + /* First, disable the interrupts to avoid potentially triggering another interrupt + * while reading out the RX FIFO as more data may be coming into the RX FIFO. We'll + * re-enable the interrupts based on the LPSPI state after reading out the FIFO. + */ + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable); + + while ((LPSPI_GetRxFifoCount(base) != 0U) && (handle->rxRemainingByteCount != 0U)) + { + /*Read out the data*/ + readData = LPSPI_ReadData(base); + + /*Decrease the read RX register times.*/ + --handle->readRegRemainingTimes; + readRegRemainingTimes = handle->readRegRemainingTimes; + + if (handle->rxRemainingByteCount < (size_t)bytesEachRead) + { + handle->bytesEachRead = (uint8_t)(handle->rxRemainingByteCount); + bytesEachRead = handle->bytesEachRead; + } + + LPSPI_SeparateReadData(handle->rxData, readData, bytesEachRead, isByteSwap); + handle->rxData += bytesEachRead; + + /*Decrease the remaining RX byte count.*/ + handle->rxRemainingByteCount -= (size_t)bytesEachRead; + } + + /* Re-enable the interrupts only if rxCount indicates there is more data to receive, + * else we may get a spurious interrupt. + * */ + if (handle->rxRemainingByteCount != 0U) + { + /* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */ + LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable); + } + } + + /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there + *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark. + */ + if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark) + { + base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | + LPSPI_FCR_RXWATER((readRegRemainingTimes > 1U) ? (readRegRemainingTimes - 1U) : (0U)); + } + } + + if (handle->txRemainingByteCount != 0U) + { + if (handle->isTxMask) + { + /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared by + hardware every time when TCR[FRAMESZ] bit of data is transfered. + In this case TCR[TXMSK] should be set to initiate each transfer. */ + base->TCR |= LPSPI_TCR_TXMSK_MASK; + if ((handle->txRemainingByteCount == (uint32_t)handle->bytesPerFrame) && (handle->isPcsContinuous)) + { + /* For the last piece of frame size of data, if is PCS continous mode(TCR[CONT]), TCR[CONTC] should + * be cleared to de-assert the PCS. Be sure to clear the TXMSK as well otherwise another FRAMESZ + * of data will be received. */ + base->TCR &= ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK | LPSPI_TCR_TXMSK_MASK); + } + handle->txRemainingByteCount -= (uint32_t)handle->bytesPerFrame; + } + else + { + LPSPI_MasterTransferFillUpTxFifo(base, handle); + } + } + else + { + if ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize))) + { + if ((handle->isPcsContinuous) && (handle->writeTcrInIsr) && (!handle->isTxMask)) + { + base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK)); + handle->writeTcrInIsr = false; + } + } + } + + if ((handle->txRemainingByteCount == 0U) && (handle->rxRemainingByteCount == 0U) && (!handle->writeTcrInIsr)) + { + /* If no RX buffer, then transfer is not complete until transfer complete flag sets */ + if (handle->rxData == NULL) + { + if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) != 0U) + { + LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_TransferCompleteFlag); + /* Complete the transfer and disable the interrupts */ + LPSPI_MasterTransferComplete(base, handle); + } + else + { + LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TransferCompleteInterruptEnable); + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable); + } + } + else + { + /* Complete the transfer and disable the interrupts */ + LPSPI_MasterTransferComplete(base, handle); + } + } +} + +/*Transactional APIs -- Slave*/ +/*! + * brief Initializes the LPSPI slave handle. + * + * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a + * specified LPSPI instance, call this API once to get the initialized handle. + * + * param base LPSPI peripheral address. + * param handle LPSPI handle pointer to lpspi_slave_handle_t. + * param callback DSPI callback. + * param userData callback function parameter. + */ +void LPSPI_SlaveTransferCreateHandle(LPSPI_Type *base, + lpspi_slave_handle_t *handle, + lpspi_slave_transfer_callback_t callback, + void *userData) +{ + assert(handle != NULL); + + /* Zero the handle. */ + (void)memset(handle, 0, sizeof(*handle)); + + s_lpspiHandle[LPSPI_GetInstance(base)] = handle; + + /* Set irq handler. */ + s_lpspiSlaveIsr = LPSPI_SlaveTransferHandleIRQ; + + handle->callback = callback; + handle->userData = userData; +} + +/*! + * brief LPSPI slave transfer data using an interrupt method. + * + * This function transfer data using an interrupt method. This is a non-blocking function, which returns right away. + * When all data is transferred, the callback function is called. + * + * Note: + * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. + * For bytesPerFrame greater than 4: + * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4. + * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. + * + * param base LPSPI peripheral address. + * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. + * param transfer pointer to lpspi_transfer_t structure. + * return status of status_t. + */ +status_t LPSPI_SlaveTransferNonBlocking(LPSPI_Type *base, lpspi_slave_handle_t *handle, lpspi_transfer_t *transfer) +{ + assert(handle != NULL); + assert(transfer != NULL); + + /* Check that we're not busy.*/ + if (handle->state == (uint8_t)kLPSPI_Busy) + { + return kStatus_LPSPI_Busy; + } + LPSPI_Enable(base, false); + /* Check arguements */ + if (!LPSPI_CheckTransferArgument(base, transfer, false)) + { + return kStatus_InvalidArgument; + } + + /* Flush FIFO, clear status, disable all the inerrupts. */ + LPSPI_FlushFifo(base, true, true); + LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag); + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); + + /* Variables */ + bool isRxMask = false; + bool isTxMask = false; + uint8_t txWatermark; + uint32_t readRegRemainingTimes; + uint32_t whichPcs = (transfer->configFlags & LPSPI_SLAVE_PCS_MASK) >> LPSPI_SLAVE_PCS_SHIFT; + uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; + + /* Assign the original value for members of transfer handle. */ + handle->state = (uint8_t)kLPSPI_Busy; + handle->txData = transfer->txData; + handle->rxData = transfer->rxData; + handle->txRemainingByteCount = transfer->dataSize; + handle->rxRemainingByteCount = transfer->dataSize; + handle->totalByteCount = transfer->dataSize; + handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U); + handle->readRegRemainingTimes = handle->writeRegRemainingTimes; + /*The TX and RX FIFO sizes are always the same*/ + handle->fifoSize = LPSPI_GetRxFifoSize(base); + handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_SlaveByteSwap) != 0U); + /*Calculate the bytes for write/read the TX/RX register each time*/ + if (bytesPerFrame <= 4U) + { + handle->bytesEachWrite = (uint8_t)bytesPerFrame; + handle->bytesEachRead = (uint8_t)bytesPerFrame; + } + else + { + handle->bytesEachWrite = 4U; + handle->bytesEachRead = 4U; + } + /* Set proper RX and TX watermarks to reduce the ISR response times. */ + if (handle->fifoSize > 1U) + { + txWatermark = 1U; + handle->rxWatermark = handle->fifoSize - 2U; + } + else + { + txWatermark = 0U; + handle->rxWatermark = 0U; + } + LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark); + + /* If there is no rxData, mask the receive data so that receive data is not stored in receive FIFO. */ + if (handle->rxData == NULL) + { + isRxMask = true; + handle->rxRemainingByteCount = 0U; + } + /* If there is no txData, mask the transmit data so that no data is loaded from transmit FIFO and output pin + * is tristated. */ + if (handle->txData == NULL) + { + isTxMask = true; + handle->txRemainingByteCount = 0U; + } + + /* Enable module for following configuration of TCR to take effect. */ + LPSPI_Enable(base, true); + + base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | + LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) | + LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_TXMSK(isTxMask) | LPSPI_TCR_PCS(whichPcs); + + /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX , + * and you should also enable the INTMUX interupt in your application. + */ + (void)EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]); + + /*TCR is also shared the FIFO, so wait for TCR written.*/ + if (!LPSPI_TxFifoReady(base)) + { + return kStatus_LPSPI_Timeout; + } + + /* Fill up the TX data in FIFO */ + if (handle->txData != NULL) + { + LPSPI_SlaveTransferFillUpTxFifo(base, handle); + } + + /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data. + * The IRQ handler will get the status of RX and TX interrupt flags. + */ + if (handle->rxData != NULL) + { + /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there + *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark. + */ + readRegRemainingTimes = handle->readRegRemainingTimes; + if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark) + { + base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(readRegRemainingTimes - 1U); + } + + /* RX request and FIFO overflow request enable */ + LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable | (uint32_t)kLPSPI_ReceiveErrorInterruptEnable); + } + else + { + LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable); + } + + if (handle->txData != NULL) + { + /* TX FIFO underflow request enable */ + LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TransmitErrorInterruptEnable); + } + + return kStatus_Success; +} + +static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle) +{ + assert(handle != NULL); + + uint32_t wordToSend = 0U; + uint8_t bytesEachWrite = handle->bytesEachWrite; + bool isByteSwap = handle->isByteSwap; + + while (LPSPI_GetTxFifoCount(base) < (handle->fifoSize)) + { + if (handle->txRemainingByteCount < (size_t)bytesEachWrite) + { + handle->bytesEachWrite = (uint8_t)handle->txRemainingByteCount; + bytesEachWrite = handle->bytesEachWrite; + } + + wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap); + handle->txData += bytesEachWrite; + + /*Decrease the remaining TX byte count.*/ + handle->txRemainingByteCount -= (size_t)bytesEachWrite; + + /*Write the word to TX register*/ + LPSPI_WriteData(base, wordToSend); + + if (handle->txRemainingByteCount == 0U) + { + break; + } + } +} + +static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle) +{ + assert(handle != NULL); + + status_t status = kStatus_Success; + + /* Disable interrupt requests*/ + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); + + if (handle->state == (uint8_t)kLPSPI_Error) + { + status = kStatus_LPSPI_Error; + } + else + { + status = kStatus_Success; + } + + handle->state = (uint8_t)kLPSPI_Idle; + + if (handle->callback != NULL) + { + handle->callback(base, handle, status, handle->userData); + } +} + +/*! + * brief Gets the slave transfer remaining bytes. + * + * This function gets the slave transfer remaining bytes. + * + * param base LPSPI peripheral address. + * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. + * param count Number of bytes transferred so far by the non-blocking transaction. + * return status of status_t. + */ +status_t LPSPI_SlaveTransferGetCount(LPSPI_Type *base, lpspi_slave_handle_t *handle, size_t *count) +{ + assert(handle != NULL); + + if (NULL == count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (handle->state != (uint8_t)kLPSPI_Busy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + size_t remainingByte; + + if (handle->rxData != NULL) + { + remainingByte = handle->rxRemainingByteCount; + } + else + { + remainingByte = handle->txRemainingByteCount; + } + + *count = handle->totalByteCount - remainingByte; + + return kStatus_Success; +} + +/*! + * brief LPSPI slave aborts a transfer which uses an interrupt method. + * + * This function aborts a transfer which uses an interrupt method. + * + * param base LPSPI peripheral address. + * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. + */ +void LPSPI_SlaveTransferAbort(LPSPI_Type *base, lpspi_slave_handle_t *handle) +{ + assert(handle != NULL); + + /* Disable interrupt requests*/ + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable); + + LPSPI_Reset(base); + + handle->state = (uint8_t)kLPSPI_Idle; + handle->txRemainingByteCount = 0U; + handle->rxRemainingByteCount = 0U; +} + +/*! + * brief LPSPI Slave IRQ handler function. + * + * This function processes the LPSPI transmit and receives an IRQ. + * + * param base LPSPI peripheral address. + * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. + */ +void LPSPI_SlaveTransferHandleIRQ(LPSPI_Type *base, lpspi_slave_handle_t *handle) +{ + assert(handle != NULL); + + uint32_t readData; /* variable to store word read from RX FIFO */ + uint8_t bytesEachRead = handle->bytesEachRead; + bool isByteSwap = handle->isByteSwap; + uint32_t readRegRemainingTimes; + + if (handle->rxData != NULL) + { + if (handle->rxRemainingByteCount > 0U) + { + while (LPSPI_GetRxFifoCount(base) != 0U) + { + /*Read out the data*/ + readData = LPSPI_ReadData(base); + + /*Decrease the read RX register times.*/ + --handle->readRegRemainingTimes; + + if (handle->rxRemainingByteCount < (size_t)bytesEachRead) + { + handle->bytesEachRead = (uint8_t)handle->rxRemainingByteCount; + bytesEachRead = handle->bytesEachRead; + } + + LPSPI_SeparateReadData(handle->rxData, readData, bytesEachRead, isByteSwap); + handle->rxData += bytesEachRead; + + /*Decrease the remaining RX byte count.*/ + handle->rxRemainingByteCount -= (size_t)bytesEachRead; + + if ((handle->txRemainingByteCount > 0U) && (handle->txData != NULL)) + { + LPSPI_SlaveTransferFillUpTxFifo(base, handle); + } + + if (handle->rxRemainingByteCount == 0U) + { + break; + } + } + } + + /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there + *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark. + */ + readRegRemainingTimes = handle->readRegRemainingTimes; + if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark) + { + base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | + LPSPI_FCR_RXWATER((readRegRemainingTimes > 1U) ? (readRegRemainingTimes - 1U) : (0U)); + } + } + if ((handle->rxData == NULL) && (handle->txRemainingByteCount != 0U) && (handle->txData != NULL)) + { + LPSPI_SlaveTransferFillUpTxFifo(base, handle); + } + + if ((handle->txRemainingByteCount == 0U) && (handle->rxRemainingByteCount == 0U)) + { + /* If no RX buffer, then transfer is not complete until transfer complete flag sets and the TX FIFO empty*/ + if (handle->rxData == NULL) + { + if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_FrameCompleteFlag) != 0U) && + (LPSPI_GetTxFifoCount(base) == 0U)) + { + LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_FrameCompleteFlag); + /* Complete the transfer and disable the interrupts */ + LPSPI_SlaveTransferComplete(base, handle); + } + else + { + LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_FrameCompleteFlag); + LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_FrameCompleteInterruptEnable); + LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable); + } + } + else + { + /* Complete the transfer and disable the interrupts */ + LPSPI_SlaveTransferComplete(base, handle); + } + } + + /* Catch tx fifo underflow conditions, service only if tx under flow interrupt enabled */ + if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransmitErrorFlag) != 0U) && + ((base->IER & LPSPI_IER_TEIE_MASK) != 0U)) + { + LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_TransmitErrorFlag); + /* Change state to error and clear flag */ + if (handle->txData != NULL) + { + handle->state = (uint8_t)kLPSPI_Error; + } + handle->errorCount++; + } + /* Catch rx fifo overflow conditions, service only if rx over flow interrupt enabled */ + if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ReceiveErrorFlag) != 0U) && + ((base->IER & LPSPI_IER_REIE_MASK) != 0U)) + { + LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_ReceiveErrorFlag); + /* Change state to error and clear flag */ + if (handle->txData != NULL) + { + handle->state = (uint8_t)kLPSPI_Error; + } + handle->errorCount++; + } +} + +static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint8_t bytesEachWrite, bool isByteSwap) +{ + assert(txData != NULL); + + uint32_t wordToSend = 0U; + + switch (bytesEachWrite) + { + case 1: + wordToSend = *txData; + ++txData; + break; + + case 2: + if (!isByteSwap) + { + wordToSend = *txData; + ++txData; + wordToSend |= (unsigned)(*txData) << 8U; + ++txData; + } + else + { + wordToSend = (unsigned)(*txData) << 8U; + ++txData; + wordToSend |= *txData; + ++txData; + } + + break; + + case 3: + if (!isByteSwap) + { + wordToSend = *txData; + ++txData; + wordToSend |= (unsigned)(*txData) << 8U; + ++txData; + wordToSend |= (unsigned)(*txData) << 16U; + ++txData; + } + else + { + wordToSend = (unsigned)(*txData) << 16U; + ++txData; + wordToSend |= (unsigned)(*txData) << 8U; + ++txData; + wordToSend |= *txData; + ++txData; + } + break; + + case 4: + if (!isByteSwap) + { + wordToSend = *txData; + ++txData; + wordToSend |= (unsigned)(*txData) << 8U; + ++txData; + wordToSend |= (unsigned)(*txData) << 16U; + ++txData; + wordToSend |= (unsigned)(*txData) << 24U; + ++txData; + } + else + { + wordToSend = (unsigned)(*txData) << 24U; + ++txData; + wordToSend |= (unsigned)(*txData) << 16U; + ++txData; + wordToSend |= (unsigned)(*txData) << 8U; + ++txData; + wordToSend |= *txData; + ++txData; + } + break; + + default: + assert(false); + break; + } + return wordToSend; +} + +static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint8_t bytesEachRead, bool isByteSwap) +{ + assert(rxData != NULL); + + switch (bytesEachRead) + { + case 1: + *rxData = (uint8_t)readData; + ++rxData; + break; + + case 2: + if (!isByteSwap) + { + *rxData = (uint8_t)readData; + ++rxData; + *rxData = (uint8_t)(readData >> 8); + ++rxData; + } + else + { + *rxData = (uint8_t)(readData >> 8); + ++rxData; + *rxData = (uint8_t)readData; + ++rxData; + } + break; + + case 3: + if (!isByteSwap) + { + *rxData = (uint8_t)readData; + ++rxData; + *rxData = (uint8_t)(readData >> 8); + ++rxData; + *rxData = (uint8_t)(readData >> 16); + ++rxData; + } + else + { + *rxData = (uint8_t)(readData >> 16); + ++rxData; + *rxData = (uint8_t)(readData >> 8); + ++rxData; + *rxData = (uint8_t)readData; + ++rxData; + } + break; + + case 4: + if (!isByteSwap) + { + *rxData = (uint8_t)readData; + ++rxData; + *rxData = (uint8_t)(readData >> 8); + ++rxData; + *rxData = (uint8_t)(readData >> 16); + ++rxData; + *rxData = (uint8_t)(readData >> 24); + ++rxData; + } + else + { + *rxData = (uint8_t)(readData >> 24); + ++rxData; + *rxData = (uint8_t)(readData >> 16); + ++rxData; + *rxData = (uint8_t)(readData >> 8); + ++rxData; + *rxData = (uint8_t)readData; + ++rxData; + } + break; + + default: + assert(false); + break; + } +} + +static bool LPSPI_TxFifoReady(LPSPI_Type *base) +{ +#if SPI_RETRY_TIMES + uint32_t waitTimes = SPI_RETRY_TIMES; + while (((uint8_t)LPSPI_GetTxFifoCount(base) != 0U) && (--waitTimes != 0U)) +#else + while ((uint8_t)LPSPI_GetTxFifoCount(base) != 0U) +#endif + { + } +#if SPI_RETRY_TIMES + if (waitTimes == 0U) + { + return false; + } +#endif + return true; +} + +static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param) +{ + if (LPSPI_IsMaster(base)) + { + s_lpspiMasterIsr(base, (lpspi_master_handle_t *)param); + } + else + { + s_lpspiSlaveIsr(base, (lpspi_slave_handle_t *)param); + } + SDK_ISR_EXIT_BARRIER; +} + +#if defined(LPSPI0) +void LPSPI0_DriverIRQHandler(void); +void LPSPI0_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[0] != NULL); + LPSPI_CommonIRQHandler(LPSPI0, s_lpspiHandle[0]); +} +#endif + +#if defined(LPSPI1) +void LPSPI1_DriverIRQHandler(void); +void LPSPI1_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[1] != NULL); + LPSPI_CommonIRQHandler(LPSPI1, s_lpspiHandle[1]); +} +#endif + +#if defined(LPSPI2) +void LPSPI2_DriverIRQHandler(void); +void LPSPI2_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[2] != NULL); + LPSPI_CommonIRQHandler(LPSPI2, s_lpspiHandle[2]); +} +#endif + +#if defined(LPSPI3) +void LPSPI3_DriverIRQHandler(void); +void LPSPI3_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[3] != NULL); + LPSPI_CommonIRQHandler(LPSPI3, s_lpspiHandle[3]); +} +#endif + +#if defined(LPSPI4) +void LPSPI4_DriverIRQHandler(void); +void LPSPI4_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[4] != NULL); + LPSPI_CommonIRQHandler(LPSPI4, s_lpspiHandle[4]); +} +#endif + +#if defined(LPSPI5) +void LPSPI5_DriverIRQHandler(void); +void LPSPI5_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[5] != NULL); + LPSPI_CommonIRQHandler(LPSPI5, s_lpspiHandle[5]); +} +#endif + +#if defined(DMA__LPSPI0) +void DMA_SPI0_INT_DriverIRQHandler(void); +void DMA_SPI0_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)] != NULL); + LPSPI_CommonIRQHandler(DMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]); +} +#endif + +#if defined(DMA__LPSPI1) +void DMA_SPI1_INT_DriverIRQHandler(void); +void DMA_SPI1_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)] != NULL); + LPSPI_CommonIRQHandler(DMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]); +} +#endif +#if defined(DMA__LPSPI2) +void DMA_SPI2_INT_DriverIRQHandler(void); +void DMA_SPI2_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)] != NULL); + LPSPI_CommonIRQHandler(DMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]); +} +#endif + +#if defined(DMA__LPSPI3) +void DMA_SPI3_INT_DriverIRQHandler(void); +void DMA_SPI3_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)] != NULL); + LPSPI_CommonIRQHandler(DMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]); +} +#endif + +#if defined(ADMA__LPSPI0) +void ADMA_SPI0_INT_DriverIRQHandler(void); +void ADMA_SPI0_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)] != NULL); + LPSPI_CommonIRQHandler(ADMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]); +} +#endif + +#if defined(ADMA__LPSPI1) +void ADMA_SPI1_INT_DriverIRQHandler(void); +void ADMA_SPI1_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)] != NULL); + LPSPI_CommonIRQHandler(ADMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]); +} +#endif +#if defined(ADMA__LPSPI2) +void ADMA_SPI2_INT_DriverIRQHandler(void); +void ADMA_SPI2_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)] != NULL); + LPSPI_CommonIRQHandler(ADMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]); +} +#endif + +#if defined(ADMA__LPSPI3) +void ADMA_SPI3_INT_DriverIRQHandler(void); +void ADMA_SPI3_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)] != NULL); + LPSPI_CommonIRQHandler(ADMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]); +} +#endif diff --git a/nxp/drivers/fsl_lpspi.h b/nxp/drivers/fsl_lpspi.h new file mode 100644 index 0000000..98a4116 --- /dev/null +++ b/nxp/drivers/fsl_lpspi.h @@ -0,0 +1,1158 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_LPSPI_H_ +#define _FSL_LPSPI_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup lpspi_driver + * @{ + */ + +/********************************************************************************************************************** + * Definitions + *********************************************************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief LPSPI driver version. */ +#define FSL_LPSPI_DRIVER_VERSION (MAKE_VERSION(2, 4, 0)) +/*@}*/ + +#ifndef LPSPI_DUMMY_DATA +/*! @brief LPSPI dummy data if no Tx data.*/ +#define LPSPI_DUMMY_DATA (0x00U) /*!< Dummy data used for tx if there is not txData. */ +#endif + +/*! @brief Retry times for waiting flag. */ +#ifndef SPI_RETRY_TIMES +#define SPI_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */ +#endif + +/*! @brief Global variable for dummy data value setting. */ +extern volatile uint8_t g_lpspiDummyData[]; + +/*! @brief Status for the LPSPI driver.*/ +enum +{ + kStatus_LPSPI_Busy = MAKE_STATUS(kStatusGroup_LPSPI, 0), /*!< LPSPI transfer is busy.*/ + kStatus_LPSPI_Error = MAKE_STATUS(kStatusGroup_LPSPI, 1), /*!< LPSPI driver error. */ + kStatus_LPSPI_Idle = MAKE_STATUS(kStatusGroup_LPSPI, 2), /*!< LPSPI is idle.*/ + kStatus_LPSPI_OutOfRange = MAKE_STATUS(kStatusGroup_LPSPI, 3), /*!< LPSPI transfer out Of range. */ + kStatus_LPSPI_Timeout = MAKE_STATUS(kStatusGroup_LPSPI, 4) /*!< LPSPI timeout polling status flags. */ +}; + +/*! @brief LPSPI status flags in SPIx_SR register.*/ +enum _lpspi_flags +{ + kLPSPI_TxDataRequestFlag = LPSPI_SR_TDF_MASK, /*!< Transmit data flag */ + kLPSPI_RxDataReadyFlag = LPSPI_SR_RDF_MASK, /*!< Receive data flag */ + kLPSPI_WordCompleteFlag = LPSPI_SR_WCF_MASK, /*!< Word Complete flag */ + kLPSPI_FrameCompleteFlag = LPSPI_SR_FCF_MASK, /*!< Frame Complete flag */ + kLPSPI_TransferCompleteFlag = LPSPI_SR_TCF_MASK, /*!< Transfer Complete flag */ + kLPSPI_TransmitErrorFlag = LPSPI_SR_TEF_MASK, /*!< Transmit Error flag (FIFO underrun) */ + kLPSPI_ReceiveErrorFlag = LPSPI_SR_REF_MASK, /*!< Receive Error flag (FIFO overrun) */ + kLPSPI_DataMatchFlag = LPSPI_SR_DMF_MASK, /*!< Data Match flag */ + kLPSPI_ModuleBusyFlag = LPSPI_SR_MBF_MASK, /*!< Module Busy flag */ + kLPSPI_AllStatusFlag = (LPSPI_SR_TDF_MASK | LPSPI_SR_RDF_MASK | LPSPI_SR_WCF_MASK | LPSPI_SR_FCF_MASK | + LPSPI_SR_TCF_MASK | LPSPI_SR_TEF_MASK | LPSPI_SR_REF_MASK | LPSPI_SR_DMF_MASK | + LPSPI_SR_MBF_MASK) /*!< Used for clearing all w1c status flags */ +}; + +/*! @brief LPSPI interrupt source.*/ +enum _lpspi_interrupt_enable +{ + kLPSPI_TxInterruptEnable = LPSPI_IER_TDIE_MASK, /*!< Transmit data interrupt enable */ + kLPSPI_RxInterruptEnable = LPSPI_IER_RDIE_MASK, /*!< Receive data interrupt enable */ + kLPSPI_WordCompleteInterruptEnable = LPSPI_IER_WCIE_MASK, /*!< Word complete interrupt enable */ + kLPSPI_FrameCompleteInterruptEnable = LPSPI_IER_FCIE_MASK, /*!< Frame complete interrupt enable */ + kLPSPI_TransferCompleteInterruptEnable = LPSPI_IER_TCIE_MASK, /*!< Transfer complete interrupt enable */ + kLPSPI_TransmitErrorInterruptEnable = LPSPI_IER_TEIE_MASK, /*!< Transmit error interrupt enable(FIFO underrun)*/ + kLPSPI_ReceiveErrorInterruptEnable = LPSPI_IER_REIE_MASK, /*!< Receive Error interrupt enable (FIFO overrun) */ + kLPSPI_DataMatchInterruptEnable = LPSPI_IER_DMIE_MASK, /*!< Data Match interrupt enable */ + kLPSPI_AllInterruptEnable = + (LPSPI_IER_TDIE_MASK | LPSPI_IER_RDIE_MASK | LPSPI_IER_WCIE_MASK | LPSPI_IER_FCIE_MASK | LPSPI_IER_TCIE_MASK | + LPSPI_IER_TEIE_MASK | LPSPI_IER_REIE_MASK | LPSPI_IER_DMIE_MASK) /*!< All above interrupts enable.*/ +}; + +/*! @brief LPSPI DMA source.*/ +enum _lpspi_dma_enable +{ + kLPSPI_TxDmaEnable = LPSPI_DER_TDDE_MASK, /*!< Transmit data DMA enable */ + kLPSPI_RxDmaEnable = LPSPI_DER_RDDE_MASK /*!< Receive data DMA enable */ +}; + +/*! @brief LPSPI master or slave mode configuration.*/ +typedef enum _lpspi_master_slave_mode +{ + kLPSPI_Master = 1U, /*!< LPSPI peripheral operates in master mode.*/ + kLPSPI_Slave = 0U /*!< LPSPI peripheral operates in slave mode.*/ +} lpspi_master_slave_mode_t; + +/*! @brief LPSPI Peripheral Chip Select (PCS) configuration (which PCS to configure).*/ +typedef enum _lpspi_which_pcs_config +{ + kLPSPI_Pcs0 = 0U, /*!< PCS[0] */ + kLPSPI_Pcs1 = 1U, /*!< PCS[1] */ + kLPSPI_Pcs2 = 2U, /*!< PCS[2] */ + kLPSPI_Pcs3 = 3U /*!< PCS[3] */ +} lpspi_which_pcs_t; + +/*! @brief LPSPI Peripheral Chip Select (PCS) Polarity configuration.*/ +typedef enum _lpspi_pcs_polarity_config +{ + kLPSPI_PcsActiveHigh = 1U, /*!< PCS Active High (idles low) */ + kLPSPI_PcsActiveLow = 0U /*!< PCS Active Low (idles high) */ +} lpspi_pcs_polarity_config_t; + +/*! @brief LPSPI Peripheral Chip Select (PCS) Polarity.*/ +enum _lpspi_pcs_polarity +{ + kLPSPI_Pcs0ActiveLow = 1U << 0, /*!< Pcs0 Active Low (idles high). */ + kLPSPI_Pcs1ActiveLow = 1U << 1, /*!< Pcs1 Active Low (idles high). */ + kLPSPI_Pcs2ActiveLow = 1U << 2, /*!< Pcs2 Active Low (idles high). */ + kLPSPI_Pcs3ActiveLow = 1U << 3, /*!< Pcs3 Active Low (idles high). */ + kLPSPI_PcsAllActiveLow = 0xFU /*!< Pcs0 to Pcs5 Active Low (idles high). */ +}; + +/*! @brief LPSPI clock polarity configuration.*/ +typedef enum _lpspi_clock_polarity +{ + kLPSPI_ClockPolarityActiveHigh = 0U, /*!< CPOL=0. Active-high LPSPI clock (idles low)*/ + kLPSPI_ClockPolarityActiveLow = 1U /*!< CPOL=1. Active-low LPSPI clock (idles high)*/ +} lpspi_clock_polarity_t; + +/*! @brief LPSPI clock phase configuration.*/ +typedef enum _lpspi_clock_phase +{ + kLPSPI_ClockPhaseFirstEdge = 0U, /*!< CPHA=0. Data is captured on the leading edge of the SCK and changed on the + following edge.*/ + kLPSPI_ClockPhaseSecondEdge = 1U /*!< CPHA=1. Data is changed on the leading edge of the SCK and captured on the + following edge.*/ +} lpspi_clock_phase_t; + +/*! @brief LPSPI data shifter direction options.*/ +typedef enum _lpspi_shift_direction +{ + kLPSPI_MsbFirst = 0U, /*!< Data transfers start with most significant bit.*/ + kLPSPI_LsbFirst = 1U /*!< Data transfers start with least significant bit.*/ +} lpspi_shift_direction_t; + +/*! @brief LPSPI Host Request select configuration. */ +typedef enum _lpspi_host_request_select +{ + kLPSPI_HostReqExtPin = 0U, /*!< Host Request is an ext pin. */ + kLPSPI_HostReqInternalTrigger = 1U /*!< Host Request is an internal trigger. */ +} lpspi_host_request_select_t; + +/*! @brief LPSPI Match configuration options. */ +typedef enum _lpspi_match_config +{ + kLPSI_MatchDisabled = 0x0U, /*!< LPSPI Match Disabled. */ + kLPSI_1stWordEqualsM0orM1 = 0x2U, /*!< LPSPI Match Enabled. */ + kLPSI_AnyWordEqualsM0orM1 = 0x3U, /*!< LPSPI Match Enabled. */ + kLPSI_1stWordEqualsM0and2ndWordEqualsM1 = 0x4U, /*!< LPSPI Match Enabled. */ + kLPSI_AnyWordEqualsM0andNxtWordEqualsM1 = 0x5U, /*!< LPSPI Match Enabled. */ + kLPSI_1stWordAndM1EqualsM0andM1 = 0x6U, /*!< LPSPI Match Enabled. */ + kLPSI_AnyWordAndM1EqualsM0andM1 = 0x7U, /*!< LPSPI Match Enabled. */ +} lpspi_match_config_t; + +/*! @brief LPSPI pin (SDO and SDI) configuration. */ +typedef enum _lpspi_pin_config +{ + kLPSPI_SdiInSdoOut = 0U, /*!< LPSPI SDI input, SDO output. */ + kLPSPI_SdiInSdiOut = 1U, /*!< LPSPI SDI input, SDI output. */ + kLPSPI_SdoInSdoOut = 2U, /*!< LPSPI SDO input, SDO output. */ + kLPSPI_SdoInSdiOut = 3U /*!< LPSPI SDO input, SDI output. */ +} lpspi_pin_config_t; + +/*! @brief LPSPI data output configuration. */ +typedef enum _lpspi_data_out_config +{ + kLpspiDataOutRetained = 0U, /*!< Data out retains last value when chip select is de-asserted */ + kLpspiDataOutTristate = 1U /*!< Data out is tristated when chip select is de-asserted */ +} lpspi_data_out_config_t; + +/*! @brief LPSPI transfer width configuration. */ +typedef enum _lpspi_transfer_width +{ + kLPSPI_SingleBitXfer = 0U, /*!< 1-bit shift at a time, data out on SDO, in on SDI (normal mode) */ + kLPSPI_TwoBitXfer = 1U, /*!< 2-bits shift out on SDO/SDI and in on SDO/SDI */ + kLPSPI_FourBitXfer = 2U /*!< 4-bits shift out on SDO/SDI/PCS[3:2] and in on SDO/SDI/PCS[3:2] */ +} lpspi_transfer_width_t; + +/*! @brief LPSPI delay type selection.*/ +typedef enum _lpspi_delay_type +{ + kLPSPI_PcsToSck = 1U, /*!< PCS-to-SCK delay. */ + kLPSPI_LastSckToPcs, /*!< Last SCK edge to PCS delay. */ + kLPSPI_BetweenTransfer /*!< Delay between transfers. */ +} lpspi_delay_type_t; + +#define LPSPI_MASTER_PCS_SHIFT (4U) /*!< LPSPI master PCS shift macro , internal used. */ +#define LPSPI_MASTER_PCS_MASK (0xF0U) /*!< LPSPI master PCS shift macro , internal used. */ + +/*! @brief Use this enumeration for LPSPI master transfer configFlags. */ +enum _lpspi_transfer_config_flag_for_master +{ + kLPSPI_MasterPcs0 = 0U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS0 signal */ + kLPSPI_MasterPcs1 = 1U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS1 signal */ + kLPSPI_MasterPcs2 = 2U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS2 signal */ + kLPSPI_MasterPcs3 = 3U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS3 signal */ + + kLPSPI_MasterPcsContinuous = 1U << 20, /*!< Is PCS signal continuous */ + + kLPSPI_MasterByteSwap = + 1U << 22 /*!< Is master swap the byte. + * For example, when want to send data 1 2 3 4 5 6 7 8 (suppose you set + * lpspi_shift_direction_t to MSB). + * 1. If you set bitPerFrame = 8 , no matter the kLPSPI_MasterByteSwapyou flag is used + * or not, the waveform is 1 2 3 4 5 6 7 8. + * 2. If you set bitPerFrame = 16 : + * (1) the waveform is 2 1 4 3 6 5 8 7 if you do not use the kLPSPI_MasterByteSwap flag. + * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_MasterByteSwap flag. + * 3. If you set bitPerFrame = 32 : + * (1) the waveform is 4 3 2 1 8 7 6 5 if you do not use the kLPSPI_MasterByteSwap flag. + * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_MasterByteSwap flag. + */ +}; + +#define LPSPI_SLAVE_PCS_SHIFT (4U) /*!< LPSPI slave PCS shift macro , internal used. */ +#define LPSPI_SLAVE_PCS_MASK (0xF0U) /*!< LPSPI slave PCS shift macro , internal used. */ + +/*! @brief Use this enumeration for LPSPI slave transfer configFlags. */ +enum _lpspi_transfer_config_flag_for_slave +{ + kLPSPI_SlavePcs0 = 0U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS0 signal */ + kLPSPI_SlavePcs1 = 1U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS1 signal */ + kLPSPI_SlavePcs2 = 2U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS2 signal */ + kLPSPI_SlavePcs3 = 3U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS3 signal */ + + kLPSPI_SlaveByteSwap = + 1U << 22 /*!< Is slave swap the byte. + * For example, when want to send data 1 2 3 4 5 6 7 8 (suppose you set + * lpspi_shift_direction_t to MSB). + * 1. If you set bitPerFrame = 8 , no matter the kLPSPI_SlaveByteSwap flag is used + * or not, the waveform is 1 2 3 4 5 6 7 8. + * 2. If you set bitPerFrame = 16 : + * (1) the waveform is 2 1 4 3 6 5 8 7 if you do not use the kLPSPI_SlaveByteSwap flag. + * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_SlaveByteSwap flag. + * 3. If you set bitPerFrame = 32 : + * (1) the waveform is 4 3 2 1 8 7 6 5 if you do not use the kLPSPI_SlaveByteSwap flag. + * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_SlaveByteSwap flag. + */ +}; + +/*! @brief LPSPI transfer state, which is used for LPSPI transactional API state machine. */ +enum _lpspi_transfer_state +{ + kLPSPI_Idle = 0x0U, /*!< Nothing in the transmitter/receiver. */ + kLPSPI_Busy, /*!< Transfer queue is not finished. */ + kLPSPI_Error /*!< Transfer error. */ +}; + +/*! @brief LPSPI master configuration structure.*/ +typedef struct _lpspi_master_config +{ + uint32_t baudRate; /*!< Baud Rate for LPSPI. */ + uint32_t bitsPerFrame; /*!< Bits per frame, minimum 8, maximum 4096.*/ + lpspi_clock_polarity_t cpol; /*!< Clock polarity. */ + lpspi_clock_phase_t cpha; /*!< Clock phase. */ + lpspi_shift_direction_t direction; /*!< MSB or LSB data shift direction. */ + + uint32_t pcsToSckDelayInNanoSec; /*!< PCS to SCK delay time in nanoseconds, setting to 0 sets the minimum delay. + It sets the boundary value if out of range.*/ + uint32_t lastSckToPcsDelayInNanoSec; /*!< Last SCK to PCS delay time in nanoseconds, setting to 0 sets the minimum + delay. It sets the boundary value if out of range.*/ + uint32_t betweenTransferDelayInNanoSec; /*!< After the SCK delay time with nanoseconds, setting to 0 sets the + minimum delay. It sets the boundary value if out of range.*/ + + lpspi_which_pcs_t whichPcs; /*!< Desired Peripheral Chip Select (PCS). */ + lpspi_pcs_polarity_config_t pcsActiveHighOrLow; /*!< Desired PCS active high or low */ + + lpspi_pin_config_t pinCfg; /*!< Configures which pins are used for input and output data + *during single bit transfers.*/ + + lpspi_data_out_config_t dataOutConfig; /*!< Configures if the output data is tristated + * between accesses (LPSPI_PCS is negated). */ + bool enableInputDelay; /*!< Enable master to sample the input data on a delayed SCK. This can help improve slave + setup time. Refer to device data sheet for specific time length. */ +} lpspi_master_config_t; + +/*! @brief LPSPI slave configuration structure.*/ +typedef struct _lpspi_slave_config +{ + uint32_t bitsPerFrame; /*!< Bits per frame, minimum 8, maximum 4096.*/ + lpspi_clock_polarity_t cpol; /*!< Clock polarity. */ + lpspi_clock_phase_t cpha; /*!< Clock phase. */ + lpspi_shift_direction_t direction; /*!< MSB or LSB data shift direction. */ + + lpspi_which_pcs_t whichPcs; /*!< Desired Peripheral Chip Select (pcs) */ + lpspi_pcs_polarity_config_t pcsActiveHighOrLow; /*!< Desired PCS active high or low */ + + lpspi_pin_config_t pinCfg; /*!< Configures which pins are used for input and output data + *during single bit transfers.*/ + + lpspi_data_out_config_t dataOutConfig; /*!< Configures if the output data is tristated + * between accesses (LPSPI_PCS is negated). */ +} lpspi_slave_config_t; + +/*! + * @brief Forward declaration of the _lpspi_master_handle typedefs. + */ +typedef struct _lpspi_master_handle lpspi_master_handle_t; + +/*! + * @brief Forward declaration of the _lpspi_slave_handle typedefs. + */ +typedef struct _lpspi_slave_handle lpspi_slave_handle_t; + +/*! + * @brief Master completion callback function pointer type. + * + * @param base LPSPI peripheral address. + * @param handle Pointer to the handle for the LPSPI master. + * @param status Success or error code describing whether the transfer is completed. + * @param userData Arbitrary pointer-dataSized value passed from the application. + */ +typedef void (*lpspi_master_transfer_callback_t)(LPSPI_Type *base, + lpspi_master_handle_t *handle, + status_t status, + void *userData); + +/*! + * @brief Slave completion callback function pointer type. + * + * @param base LPSPI peripheral address. + * @param handle Pointer to the handle for the LPSPI slave. + * @param status Success or error code describing whether the transfer is completed. + * @param userData Arbitrary pointer-dataSized value passed from the application. + */ +typedef void (*lpspi_slave_transfer_callback_t)(LPSPI_Type *base, + lpspi_slave_handle_t *handle, + status_t status, + void *userData); + +/*! @brief LPSPI master/slave transfer structure.*/ +typedef struct _lpspi_transfer +{ + uint8_t *txData; /*!< Send buffer. */ + uint8_t *rxData; /*!< Receive buffer. */ + volatile size_t dataSize; /*!< Transfer bytes. */ + + uint32_t configFlags; /*!< Transfer transfer configuration flags. Set from _lpspi_transfer_config_flag_for_master if + the transfer is used for master or _lpspi_transfer_config_flag_for_slave enumeration if the + transfer is used for slave.*/ +} lpspi_transfer_t; + +/*! @brief LPSPI master transfer handle structure used for transactional API. */ +struct _lpspi_master_handle +{ + volatile bool isPcsContinuous; /*!< Is PCS continuous in transfer. */ + volatile bool writeTcrInIsr; /*!< A flag that whether should write TCR in ISR. */ + + volatile bool isByteSwap; /*!< A flag that whether should byte swap. */ + volatile bool isTxMask; /*!< A flag that whether TCR[TXMSK] is set. */ + volatile uint16_t bytesPerFrame; /*!< Number of bytes in each frame */ + + volatile uint8_t fifoSize; /*!< FIFO dataSize. */ + + volatile uint8_t rxWatermark; /*!< Rx watermark. */ + + volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */ + volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */ + + uint8_t *volatile txData; /*!< Send buffer. */ + uint8_t *volatile rxData; /*!< Receive buffer. */ + volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/ + volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/ + + volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */ + volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */ + + uint32_t totalByteCount; /*!< Number of transfer bytes*/ + + uint32_t txBuffIfNull; /*!< Used if the txData is NULL. */ + + volatile uint8_t state; /*!< LPSPI transfer state , _lpspi_transfer_state.*/ + + lpspi_master_transfer_callback_t callback; /*!< Completion callback. */ + void *userData; /*!< Callback user data. */ +}; + +/*! @brief LPSPI slave transfer handle structure used for transactional API. */ +struct _lpspi_slave_handle +{ + volatile bool isByteSwap; /*!< A flag that whether should byte swap. */ + + volatile uint8_t fifoSize; /*!< FIFO dataSize. */ + + volatile uint8_t rxWatermark; /*!< Rx watermark. */ + + volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */ + volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */ + + uint8_t *volatile txData; /*!< Send buffer. */ + uint8_t *volatile rxData; /*!< Receive buffer. */ + + volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/ + volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/ + + volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */ + volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */ + + uint32_t totalByteCount; /*!< Number of transfer bytes*/ + + volatile uint8_t state; /*!< LPSPI transfer state , _lpspi_transfer_state.*/ + + volatile uint32_t errorCount; /*!< Error count for slave transfer.*/ + + lpspi_slave_transfer_callback_t callback; /*!< Completion callback. */ + void *userData; /*!< Callback user data. */ +}; + +/********************************************************************************************************************** + * API + *********************************************************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /*_cplusplus*/ + +/*! + * @name Initialization and deinitialization + * @{ + */ + +/*! + * @brief Initializes the LPSPI master. + * + * @param base LPSPI peripheral address. + * @param masterConfig Pointer to structure lpspi_master_config_t. + * @param srcClock_Hz Module source input clock in Hertz + */ +void LPSPI_MasterInit(LPSPI_Type *base, const lpspi_master_config_t *masterConfig, uint32_t srcClock_Hz); + +/*! + * @brief Sets the lpspi_master_config_t structure to default values. + * + * This API initializes the configuration structure for LPSPI_MasterInit(). + * The initialized structure can remain unchanged in LPSPI_MasterInit(), or can be modified + * before calling the LPSPI_MasterInit(). + * Example: + * @code + * lpspi_master_config_t masterConfig; + * LPSPI_MasterGetDefaultConfig(&masterConfig); + * @endcode + * @param masterConfig pointer to lpspi_master_config_t structure + */ +void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig); + +/*! + * @brief LPSPI slave configuration. + * + * @param base LPSPI peripheral address. + * @param slaveConfig Pointer to a structure lpspi_slave_config_t. + */ +void LPSPI_SlaveInit(LPSPI_Type *base, const lpspi_slave_config_t *slaveConfig); + +/*! + * @brief Sets the lpspi_slave_config_t structure to default values. + * + * This API initializes the configuration structure for LPSPI_SlaveInit(). + * The initialized structure can remain unchanged in LPSPI_SlaveInit() or can be modified + * before calling the LPSPI_SlaveInit(). + * Example: + * @code + * lpspi_slave_config_t slaveConfig; + * LPSPI_SlaveGetDefaultConfig(&slaveConfig); + * @endcode + * @param slaveConfig pointer to lpspi_slave_config_t structure. + */ +void LPSPI_SlaveGetDefaultConfig(lpspi_slave_config_t *slaveConfig); + +/*! + * @brief De-initializes the LPSPI peripheral. Call this API to disable the LPSPI clock. + * @param base LPSPI peripheral address. + */ +void LPSPI_Deinit(LPSPI_Type *base); + +/*! + * @brief Restores the LPSPI peripheral to reset state. Note that this function + * sets all registers to reset state. As a result, the LPSPI module can't work after calling + * this API. + * @param base LPSPI peripheral address. + */ +void LPSPI_Reset(LPSPI_Type *base); + +/*! + * @brief Get the LPSPI instance from peripheral base address. + * + * @param base LPSPI peripheral base address. + * @return LPSPI instance. + */ +uint32_t LPSPI_GetInstance(LPSPI_Type *base); + +/*! + * @brief Enables the LPSPI peripheral and sets the MCR MDIS to 0. + * + * @param base LPSPI peripheral address. + * @param enable Pass true to enable module, false to disable module. + */ +static inline void LPSPI_Enable(LPSPI_Type *base, bool enable) +{ + if (enable) + { + base->CR |= LPSPI_CR_MEN_MASK; + } + else + { + base->CR &= ~LPSPI_CR_MEN_MASK; + } +} + +/*! + *@} + */ + +/*! + * @name Status + * @{ + */ + +/*! + * @brief Gets the LPSPI status flag state. + * @param base LPSPI peripheral address. + * @return The LPSPI status(in SR register). + */ +static inline uint32_t LPSPI_GetStatusFlags(LPSPI_Type *base) +{ + return (base->SR); +} + +/*! + * @brief Gets the LPSPI Tx FIFO size. + * @param base LPSPI peripheral address. + * @return The LPSPI Tx FIFO size. + */ +static inline uint8_t LPSPI_GetTxFifoSize(LPSPI_Type *base) +{ + return (1U << ((base->PARAM & LPSPI_PARAM_TXFIFO_MASK) >> LPSPI_PARAM_TXFIFO_SHIFT)); +} + +/*! + * @brief Gets the LPSPI Rx FIFO size. + * @param base LPSPI peripheral address. + * @return The LPSPI Rx FIFO size. + */ +static inline uint8_t LPSPI_GetRxFifoSize(LPSPI_Type *base) +{ + return (1U << ((base->PARAM & LPSPI_PARAM_RXFIFO_MASK) >> LPSPI_PARAM_RXFIFO_SHIFT)); +} + +/*! + * @brief Gets the LPSPI Tx FIFO count. + * @param base LPSPI peripheral address. + * @return The number of words in the transmit FIFO. + */ +static inline uint32_t LPSPI_GetTxFifoCount(LPSPI_Type *base) +{ + return ((base->FSR & LPSPI_FSR_TXCOUNT_MASK) >> LPSPI_FSR_TXCOUNT_SHIFT); +} + +/*! + * @brief Gets the LPSPI Rx FIFO count. + * @param base LPSPI peripheral address. + * @return The number of words in the receive FIFO. + */ +static inline uint32_t LPSPI_GetRxFifoCount(LPSPI_Type *base) +{ + return ((base->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT); +} + +/*! + * @brief Clears the LPSPI status flag. + * + * This function clears the desired status bit by using a write-1-to-clear. The user passes in the base and the + * desired status flag bit to clear. The list of status flags is defined in the _lpspi_flags. + * Example usage: + * @code + * LPSPI_ClearStatusFlags(base, kLPSPI_TxDataRequestFlag|kLPSPI_RxDataReadyFlag); + * @endcode + * + * @param base LPSPI peripheral address. + * @param statusFlags The status flag used from type _lpspi_flags. + */ +static inline void LPSPI_ClearStatusFlags(LPSPI_Type *base, uint32_t statusFlags) +{ + base->SR = statusFlags; /*!< The status flags are cleared by writing 1 (w1c).*/ +} + +/*! + *@} + */ + +/*! + * @name Interrupts + * @{ + */ + +/*! + * @brief Enables the LPSPI interrupts. + * + * This function configures the various interrupt masks of the LPSPI. The parameters are base and an interrupt mask. + * Note that, for Tx fill and Rx FIFO drain requests, enabling the interrupt request disables the DMA request. + * + * @code + * LPSPI_EnableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable ); + * @endcode + * + * @param base LPSPI peripheral address. + * @param mask The interrupt mask; Use the enum _lpspi_interrupt_enable. + */ +static inline void LPSPI_EnableInterrupts(LPSPI_Type *base, uint32_t mask) +{ + base->IER |= mask; +} + +/*! + * @brief Disables the LPSPI interrupts. + * + * @code + * LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable ); + * @endcode + * + * @param base LPSPI peripheral address. + * @param mask The interrupt mask; Use the enum _lpspi_interrupt_enable. + */ +static inline void LPSPI_DisableInterrupts(LPSPI_Type *base, uint32_t mask) +{ + base->IER &= ~mask; +} + +/*! + *@} + */ + +/*! + * @name DMA Control + * @{ + */ + +/*! + * @brief Enables the LPSPI DMA request. + * + * This function configures the Rx and Tx DMA mask of the LPSPI. The parameters are base and a DMA mask. + * @code + * LPSPI_EnableDMA(base, kLPSPI_TxDmaEnable | kLPSPI_RxDmaEnable); + * @endcode + * + * @param base LPSPI peripheral address. + * @param mask The interrupt mask; Use the enum _lpspi_dma_enable. + */ +static inline void LPSPI_EnableDMA(LPSPI_Type *base, uint32_t mask) +{ + base->DER |= mask; +} + +/*! + * @brief Disables the LPSPI DMA request. + * + * This function configures the Rx and Tx DMA mask of the LPSPI. The parameters are base and a DMA mask. + * @code + * SPI_DisableDMA(base, kLPSPI_TxDmaEnable | kLPSPI_RxDmaEnable); + * @endcode + * + * @param base LPSPI peripheral address. + * @param mask The interrupt mask; Use the enum _lpspi_dma_enable. + */ +static inline void LPSPI_DisableDMA(LPSPI_Type *base, uint32_t mask) +{ + base->DER &= ~mask; +} + +/*! + * @brief Gets the LPSPI Transmit Data Register address for a DMA operation. + * + * This function gets the LPSPI Transmit Data Register address because this value is needed + * for the DMA operation. + * This function can be used for either master or slave mode. + * + * @param base LPSPI peripheral address. + * @return The LPSPI Transmit Data Register address. + */ +static inline uint32_t LPSPI_GetTxRegisterAddress(LPSPI_Type *base) +{ + return (uint32_t) & (base->TDR); +} + +/*! + * @brief Gets the LPSPI Receive Data Register address for a DMA operation. + * + * This function gets the LPSPI Receive Data Register address because this value is needed + * for the DMA operation. + * This function can be used for either master or slave mode. + * + * @param base LPSPI peripheral address. + * @return The LPSPI Receive Data Register address. + */ +static inline uint32_t LPSPI_GetRxRegisterAddress(LPSPI_Type *base) +{ + return (uint32_t) & (base->RDR); +} + +/*! + *@} + */ + +/*! + * @name Bus Operations + * @{ + */ + +/*! + * @brief Check the argument for transfer . + * + * @param base LPSPI peripheral address. + * @param transfer the transfer struct to be used. + * @param isEdma True to check for EDMA transfer, false to check interrupt non-blocking transfer + * @return Return true for right and false for wrong. + */ +bool LPSPI_CheckTransferArgument(LPSPI_Type *base, lpspi_transfer_t *transfer, bool isEdma); + +/*! + * @brief Configures the LPSPI for either master or slave. + * + * Note that the CFGR1 should only be written when the LPSPI is disabled (LPSPIx_CR_MEN = 0). + * + * @param base LPSPI peripheral address. + * @param mode Mode setting (master or slave) of type lpspi_master_slave_mode_t. + */ +static inline void LPSPI_SetMasterSlaveMode(LPSPI_Type *base, lpspi_master_slave_mode_t mode) +{ + base->CFGR1 = (base->CFGR1 & (~LPSPI_CFGR1_MASTER_MASK)) | LPSPI_CFGR1_MASTER(mode); +} + +/*! + * @brief Configures the peripheral chip select used for the transfer. + * + * @param base LPSPI peripheral address. + * @param select LPSPI Peripheral Chip Select (PCS) configuration. + */ +static inline void LPSPI_SelectTransferPCS(LPSPI_Type *base, lpspi_which_pcs_t select) +{ + base->TCR = (base->TCR & (~LPSPI_TCR_PCS_MASK)) | LPSPI_TCR_PCS((uint8_t)select); +} + +/*! + * @brief Set the PCS signal to continuous or uncontinuous mode. + * + * @note In master mode, continuous transfer will keep the PCS asserted at the end of the frame size, until a command + * word is received that starts a new frame. So PCS must be set back to uncontinuous when transfer finishes. + * In slave mode, when continuous transfer is enabled, the LPSPI will only transmit the first frame size bits, after + * that the LPSPI will transmit received data back (assuming a 32-bit shift register). + * + * @param base LPSPI peripheral address. + * @param IsContinous True to set the transfer PCS to continuous mode, false to set to uncontinuous mode. + */ +static inline void LPSPI_SetPCSContinous(LPSPI_Type *base, bool IsContinous) +{ + if (IsContinous) + { + base->TCR |= LPSPI_TCR_CONT_MASK; + } + else + { + base->TCR &= ~LPSPI_TCR_CONT_MASK; + } +} + +/*! + * @brief Returns whether the LPSPI module is in master mode. + * + * @param base LPSPI peripheral address. + * @return Returns true if the module is in master mode or false if the module is in slave mode. + */ +static inline bool LPSPI_IsMaster(LPSPI_Type *base) +{ + return (bool)((base->CFGR1) & LPSPI_CFGR1_MASTER_MASK); +} + +/*! + * @brief Flushes the LPSPI FIFOs. + * + * @param base LPSPI peripheral address. + * @param flushTxFifo Flushes (true) the Tx FIFO, else do not flush (false) the Tx FIFO. + * @param flushRxFifo Flushes (true) the Rx FIFO, else do not flush (false) the Rx FIFO. + */ +static inline void LPSPI_FlushFifo(LPSPI_Type *base, bool flushTxFifo, bool flushRxFifo) +{ + base->CR |= ((uint32_t)flushTxFifo << LPSPI_CR_RTF_SHIFT) | ((uint32_t)flushRxFifo << LPSPI_CR_RRF_SHIFT); +} + +/*! + * @brief Sets the transmit and receive FIFO watermark values. + * + * This function allows the user to set the receive and transmit FIFO watermarks. The function + * does not compare the watermark settings to the FIFO size. The FIFO watermark should not be + * equal to or greater than the FIFO size. It is up to the higher level driver to make this check. + * + * @param base LPSPI peripheral address. + * @param txWater The TX FIFO watermark value. Writing a value equal or greater than the FIFO size is truncated. + * @param rxWater The RX FIFO watermark value. Writing a value equal or greater than the FIFO size is truncated. + */ +static inline void LPSPI_SetFifoWatermarks(LPSPI_Type *base, uint32_t txWater, uint32_t rxWater) +{ + base->FCR = LPSPI_FCR_TXWATER(txWater) | LPSPI_FCR_RXWATER(rxWater); +} + +/*! + * @brief Configures all LPSPI peripheral chip select polarities simultaneously. + * + * Note that the CFGR1 should only be written when the LPSPI is disabled (LPSPIx_CR_MEN = 0). + * + * This is an example: PCS0 and PCS1 set to active low and other PCSs set to active high. Note that the number of + * PCS is device-specific. + * @code + * LPSPI_SetAllPcsPolarity(base, kLPSPI_Pcs0ActiveLow | kLPSPI_Pcs1ActiveLow); + * @endcode + * + * @param base LPSPI peripheral address. + * @param mask The PCS polarity mask; Use the enum _lpspi_pcs_polarity. + */ +static inline void LPSPI_SetAllPcsPolarity(LPSPI_Type *base, uint32_t mask) +{ + base->CFGR1 = (base->CFGR1 & ~LPSPI_CFGR1_PCSPOL_MASK) | LPSPI_CFGR1_PCSPOL(~mask); +} + +/*! + * @brief Configures the frame size. + * + * The minimum frame size is 8-bits and the maximum frame size is 4096-bits. If the frame size is less than or equal + * to 32-bits, the word size and frame size are identical. If the frame size is greater than 32-bits, the word + * size is 32-bits for each word except the last (the last word contains the remainder bits if the frame size is not + * divisible by 32). The minimum word size is 2-bits. A frame size of 33-bits (or similar) is not supported. + * + * Note 1: The transmit command register should be initialized before enabling the LPSPI in slave mode, although + * the command register does not update until after the LPSPI is enabled. After it is enabled, the transmit command + * register + * should only be changed if the LPSPI is idle. + * + * Note 2: The transmit and command FIFO is a combined FIFO that includes both transmit data and command words. That + * means the TCR register should be written to when the Tx FIFO is not full. + * + * @param base LPSPI peripheral address. + * @param frameSize The frame size in number of bits. + */ +static inline void LPSPI_SetFrameSize(LPSPI_Type *base, uint32_t frameSize) +{ + base->TCR = (base->TCR & ~LPSPI_TCR_FRAMESZ_MASK) | LPSPI_TCR_FRAMESZ(frameSize - 1U); +} + +/*! + * @brief Sets the LPSPI baud rate in bits per second. + * + * This function takes in the desired bitsPerSec (baud rate) and calculates the nearest + * possible baud rate without exceeding the desired baud rate and returns the + * calculated baud rate in bits-per-second. It requires the caller to provide + * the frequency of the module source clock (in Hertz). Note that the baud rate + * does not go into effect until the Transmit Control Register (TCR) is programmed + * with the prescale value. Hence, this function returns the prescale tcrPrescaleValue + * parameter for later programming in the TCR. The higher level + * peripheral driver should alert the user of an out of range baud rate input. + * + * Note that the LPSPI module must first be disabled before configuring this. + * Note that the LPSPI module must be configured for master mode before configuring this. + * + * @param base LPSPI peripheral address. + * @param baudRate_Bps The desired baud rate in bits per second. + * @param srcClock_Hz Module source input clock in Hertz. + * @param tcrPrescaleValue The TCR prescale value needed to program the TCR. + * @return The actual calculated baud rate. This function may also return a "0" if the + * LPSPI is not configured for master mode or if the LPSPI module is not disabled. + */ + +uint32_t LPSPI_MasterSetBaudRate(LPSPI_Type *base, + uint32_t baudRate_Bps, + uint32_t srcClock_Hz, + uint32_t *tcrPrescaleValue); + +/*! + * @brief Manually configures a specific LPSPI delay parameter (module must be disabled to + * change the delay values). + * + * This function configures the following: + * SCK to PCS delay, or + * PCS to SCK delay, or + * The configurations must occur between the transfer delay. + * + * The delay names are available in type lpspi_delay_type_t. + * + * The user passes the desired delay along with the delay value. + * This allows the user to directly set the delay values if they have + * pre-calculated them or if they simply wish to manually increment the value. + * + * Note that the LPSPI module must first be disabled before configuring this. + * Note that the LPSPI module must be configured for master mode before configuring this. + * + * @param base LPSPI peripheral address. + * @param scaler The 8-bit delay value 0x00 to 0xFF (255). + * @param whichDelay The desired delay to configure, must be of type lpspi_delay_type_t. + */ +void LPSPI_MasterSetDelayScaler(LPSPI_Type *base, uint32_t scaler, lpspi_delay_type_t whichDelay); + +/*! + * @brief Calculates the delay based on the desired delay input in nanoseconds (module must be + * disabled to change the delay values). + * + * This function calculates the values for the following: + * SCK to PCS delay, or + * PCS to SCK delay, or + * The configurations must occur between the transfer delay. + * + * The delay names are available in type lpspi_delay_type_t. + * + * The user passes the desired delay and the desired delay value in + * nano-seconds. The function calculates the value needed for the desired delay parameter + * and returns the actual calculated delay because an exact delay match may not be possible. In this + * case, the closest match is calculated without going below the desired delay value input. + * It is possible to input a very large delay value that exceeds the capability of the part, in + * which case the maximum supported delay is returned. It is up to the higher level + * peripheral driver to alert the user of an out of range delay input. + * + * Note that the LPSPI module must be configured for master mode before configuring this. And note that + * the delayTime = LPSPI_clockSource / (PRESCALE * Delay_scaler). + * + * @param base LPSPI peripheral address. + * @param delayTimeInNanoSec The desired delay value in nano-seconds. + * @param whichDelay The desired delay to configuration, which must be of type lpspi_delay_type_t. + * @param srcClock_Hz Module source input clock in Hertz. + * @return actual Calculated delay value in nano-seconds. + */ +uint32_t LPSPI_MasterSetDelayTimes(LPSPI_Type *base, + uint32_t delayTimeInNanoSec, + lpspi_delay_type_t whichDelay, + uint32_t srcClock_Hz); + +/*! + * @brief Writes data into the transmit data buffer. + * + * This function writes data passed in by the user to the Transmit Data Register (TDR). + * The user can pass up to 32-bits of data to load into the TDR. If the frame size exceeds 32-bits, + * the user has to manage sending the data one 32-bit word at a time. + * Any writes to the TDR result in an immediate push to the transmit FIFO. + * This function can be used for either master or slave modes. + * + * @param base LPSPI peripheral address. + * @param data The data word to be sent. + */ +static inline void LPSPI_WriteData(LPSPI_Type *base, uint32_t data) +{ + base->TDR = data; +} + +/*! + * @brief Reads data from the data buffer. + * + * This function reads the data from the Receive Data Register (RDR). + * This function can be used for either master or slave mode. + * + * @param base LPSPI peripheral address. + * @return The data read from the data buffer. + */ +static inline uint32_t LPSPI_ReadData(LPSPI_Type *base) +{ + return (base->RDR); +} + +/*! + * @brief Set up the dummy data. + * + * @param base LPSPI peripheral address. + * @param dummyData Data to be transferred when tx buffer is NULL. + * Note: + * This API has no effect when LPSPI in slave interrupt mode, because driver + * will set the TXMSK bit to 1 if txData is NULL, no data is loaded from transmit + * FIFO and output pin is tristated. + */ +void LPSPI_SetDummyData(LPSPI_Type *base, uint8_t dummyData); + +/*! + *@} + */ + +/*! + * @name Transactional + * @{ + */ +/*Transactional APIs*/ + +/*! + * @brief Initializes the LPSPI master handle. + * + * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a + * specified LPSPI instance, call this API once to get the initialized handle. + + * @param base LPSPI peripheral address. + * @param handle LPSPI handle pointer to lpspi_master_handle_t. + * @param callback DSPI callback. + * @param userData callback function parameter. + */ +void LPSPI_MasterTransferCreateHandle(LPSPI_Type *base, + lpspi_master_handle_t *handle, + lpspi_master_transfer_callback_t callback, + void *userData); + +/*! + * @brief LPSPI master transfer data using a polling method. + * + * This function transfers data using a polling method. This is a blocking function, which does not return until all + * transfers have been + * completed. + * + * Note: + * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. + * For bytesPerFrame greater than 4: + * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4. + * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. + * + * @param base LPSPI peripheral address. + * @param transfer pointer to lpspi_transfer_t structure. + * @return status of status_t. + */ +status_t LPSPI_MasterTransferBlocking(LPSPI_Type *base, lpspi_transfer_t *transfer); + +/*! + * @brief LPSPI master transfer data using an interrupt method. + * + * This function transfers data using an interrupt method. This is a non-blocking function, which returns right away. + * When all data is transferred, the callback function is called. + * + * Note: + * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. + * For bytesPerFrame greater than 4: + * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4. + * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. + * + * @param base LPSPI peripheral address. + * @param handle pointer to lpspi_master_handle_t structure which stores the transfer state. + * @param transfer pointer to lpspi_transfer_t structure. + * @return status of status_t. + */ +status_t LPSPI_MasterTransferNonBlocking(LPSPI_Type *base, lpspi_master_handle_t *handle, lpspi_transfer_t *transfer); + +/*! + * @brief Gets the master transfer remaining bytes. + * + * This function gets the master transfer remaining bytes. + * + * @param base LPSPI peripheral address. + * @param handle pointer to lpspi_master_handle_t structure which stores the transfer state. + * @param count Number of bytes transferred so far by the non-blocking transaction. + * @return status of status_t. + */ +status_t LPSPI_MasterTransferGetCount(LPSPI_Type *base, lpspi_master_handle_t *handle, size_t *count); + +/*! + * @brief LPSPI master abort transfer which uses an interrupt method. + * + * This function aborts a transfer which uses an interrupt method. + * + * @param base LPSPI peripheral address. + * @param handle pointer to lpspi_master_handle_t structure which stores the transfer state. + */ +void LPSPI_MasterTransferAbort(LPSPI_Type *base, lpspi_master_handle_t *handle); + +/*! + * @brief LPSPI Master IRQ handler function. + * + * This function processes the LPSPI transmit and receive IRQ. + * + * @param base LPSPI peripheral address. + * @param handle pointer to lpspi_master_handle_t structure which stores the transfer state. + */ +void LPSPI_MasterTransferHandleIRQ(LPSPI_Type *base, lpspi_master_handle_t *handle); + +/*! + * @brief Initializes the LPSPI slave handle. + * + * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a + * specified LPSPI instance, call this API once to get the initialized handle. + * + * @param base LPSPI peripheral address. + * @param handle LPSPI handle pointer to lpspi_slave_handle_t. + * @param callback DSPI callback. + * @param userData callback function parameter. + */ +void LPSPI_SlaveTransferCreateHandle(LPSPI_Type *base, + lpspi_slave_handle_t *handle, + lpspi_slave_transfer_callback_t callback, + void *userData); + +/*! + * @brief LPSPI slave transfer data using an interrupt method. + * + * This function transfer data using an interrupt method. This is a non-blocking function, which returns right away. + * When all data is transferred, the callback function is called. + * + * Note: + * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. + * For bytesPerFrame greater than 4: + * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4. + * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. + * + * @param base LPSPI peripheral address. + * @param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. + * @param transfer pointer to lpspi_transfer_t structure. + * @return status of status_t. + */ +status_t LPSPI_SlaveTransferNonBlocking(LPSPI_Type *base, lpspi_slave_handle_t *handle, lpspi_transfer_t *transfer); + +/*! + * @brief Gets the slave transfer remaining bytes. + * + * This function gets the slave transfer remaining bytes. + * + * @param base LPSPI peripheral address. + * @param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. + * @param count Number of bytes transferred so far by the non-blocking transaction. + * @return status of status_t. + */ +status_t LPSPI_SlaveTransferGetCount(LPSPI_Type *base, lpspi_slave_handle_t *handle, size_t *count); + +/*! + * @brief LPSPI slave aborts a transfer which uses an interrupt method. + * + * This function aborts a transfer which uses an interrupt method. + * + * @param base LPSPI peripheral address. + * @param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. + */ +void LPSPI_SlaveTransferAbort(LPSPI_Type *base, lpspi_slave_handle_t *handle); + +/*! + * @brief LPSPI Slave IRQ handler function. + * + * This function processes the LPSPI transmit and receives an IRQ. + * + * @param base LPSPI peripheral address. + * @param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. + */ +void LPSPI_SlaveTransferHandleIRQ(LPSPI_Type *base, lpspi_slave_handle_t *handle); + +/*! + *@} + */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /*_FSL_LPSPI_H_*/ diff --git a/nxp/nxp.mex b/nxp/nxp.mex index ace1423..2a05c6a 100644 --- a/nxp/nxp.mex +++ b/nxp/nxp.mex @@ -132,9 +132,9 @@ - + - + @@ -225,7 +225,7 @@ - + Configures pin routing and optionally pin electrical features. true @@ -233,7 +233,154 @@ true - + + + true + + + + + + + Configures pin routing and optionally pin electrical features. + + true + core0 + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Configures pin routing and optionally pin electrical features. + + true + core0 + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + Configures pin routing and optionally pin electrical features. + + true + core0 + true + + + true @@ -294,89 +441,6 @@ - - Configures pin routing and optionally pin electrical features. - - true - core0 - true - - - - - true - - - - - true - - - - - true - - - - - true - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/nxp/source/nxp.c b/nxp/source/nxp.c index 8c3bfe7..fd45c91 100644 --- a/nxp/source/nxp.c +++ b/nxp/source/nxp.c @@ -43,6 +43,8 @@ #include "fsl_lpuart.h" #include "fsl_dcp.h" #include "fsl_gpt.h" +#include "fsl_lpi2c.h" +#include "fsl_lpspi.h" #include "hal.h" struct gpio_pin_spec { @@ -52,7 +54,9 @@ struct gpio_pin_spec { struct gpio_pin_spec NXP_PIN_MAP[] = { {BOARD_CAMERA_PWDN_GPIO, BOARD_CAMERA_PWDN_PIN}, - {NULL, 0}, //{BOARD_CAMERA_RST_GPIO, BOARD_CAMERA_RST_PIN}, + {BOARD_CAMERA_RST_GPIO, BOARD_CAMERA_RST_PIN}, + {BOARD_LCD_CD_GPIO, BOARD_LCD_CD_PIN}, + {BOARD_LCD_RST_GPIO, BOARD_LCD_RST_PIN}, }; static dcp_handle_t sha256_handle; @@ -67,35 +71,49 @@ hal_err_t hal_init(void) { BOARD_InitDebugConsole(); #endif - BOARD_LPI2C_Init(BOARD_CAMERA_I2C_BASEADDR, BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT); - trng_config_t trngConfig; - TRNG_GetDefaultConfig(&trngConfig); - TRNG_Init(TRNG, &trngConfig); + BOARD_IO_Init(); - dcp_config_t dcpConfig; - DCP_GetDefaultConfig(&dcpConfig); - DCP_Init(DCP, &dcpConfig); - - sha256_handle.channel = kDCP_Channel0; - - gpt_config_t gptCfg; - GPT_GetDefaultConfig(&gptCfg); - gptCfg.clockSource = kGPT_ClockSource_Osc; - gptCfg.enableFreeRun = true; - gptCfg.enableMode = true; - gptCfg.divider = 24; - GPT_Init(GPT1, &gptCfg); + BOARD_Crypto_Init(&sha256_handle); + BOARD_Timer_Init(); return HAL_OK; } hal_err_t hal_i2c_send(hal_i2c_port_t port, uint8_t addr, const uint8_t* data, size_t len) { assert(port == I2C_CAMERA); - return BOARD_LPI2C_Send(BOARD_CAMERA_I2C_BASEADDR, addr, 0, 0, (uint8_t*) data, len) == kStatus_Success ? HAL_OK : HAL_ERROR; + + lpi2c_master_transfer_t xfer; + + xfer.flags = kLPI2C_TransferDefaultFlag; + xfer.slaveAddress = addr; + xfer.direction = kLPI2C_Write; + xfer.subaddress = 0; + xfer.subaddressSize = 0; + xfer.data = (uint8_t*) data; + xfer.dataSize = len; + + return LPI2C_MasterTransferBlocking(BOARD_CAMERA_I2C_BASEADDR, &xfer) == kStatus_Success ? HAL_OK : HAL_ERROR; +} + +hal_err_t hal_spi_send(hal_spi_port_t port, const uint8_t* data, size_t len) { + assert(port == SPI_LCD); + + lpspi_transfer_t xfer = { 0 }; + xfer.txData = (uint8_t*) data; + xfer.dataSize = len; + + return LPSPI_MasterTransferBlocking(BOARD_LCD_SPI_BASEADDR, &xfer) == kStatus_Success ? HAL_OK : HAL_ERROR; +} + +hal_err_t hal_spi_send_dma(hal_spi_port_t port, const uint8_t* data, size_t len) { + return HAL_ERROR; } hal_err_t hal_gpio_set(hal_gpio_pin_t pin, hal_gpio_state_t state) { - if (pin == GPIO_CAMERA_RST) return HAL_OK; // dev board does not connect this PIN, will connect in real board though + if (NXP_PIN_MAP[pin].base == NULL) { + return HAL_OK; // unconnected PIN + } + GPIO_WritePinOutput(NXP_PIN_MAP[pin].base, NXP_PIN_MAP[pin].pin, state); return HAL_OK; }