diff --git a/APP_Framework/Applications/connection_app/socket_demo/lwip_tcp_socket_demo.c b/APP_Framework/Applications/connection_app/socket_demo/lwip_tcp_socket_demo.c index b018be453..3eccb8dc0 100755 --- a/APP_Framework/Applications/connection_app/socket_demo/lwip_tcp_socket_demo.c +++ b/APP_Framework/Applications/connection_app/socket_demo/lwip_tcp_socket_demo.c @@ -28,6 +28,8 @@ * Definitions ******************************************************************************/ +#define TCP_DEMO_BUF_SIZE 65535 + /******************************************************************************* * Prototypes ******************************************************************************/ @@ -38,8 +40,6 @@ char tcp_socket_ip[] = {192, 168, 250, 252}; -#define TCP_DEMO_BUF_SIZE 65535 - /******************************************************************************* * Code ******************************************************************************/ @@ -80,7 +80,7 @@ static void tcp_recv_demo(void *arg) } lw_print("tcp bind success, start to receive.\n"); - lw_print("\n\nLocal Port:%d\n\n", LWIP_LOCAL_PORT); + lw_pr_info("\n\nLocal Port:%d\n\n", LWIP_LOCAL_PORT); // setup socket fd as listening mode if (listen(fd, 5) != 0 ) @@ -91,7 +91,7 @@ static void tcp_recv_demo(void *arg) // accept client connection clientfd = accept(fd, (struct sockaddr *)&tcp_addr, (socklen_t*)&addr_len); - lw_print("client %s connected\n", inet_ntoa(tcp_addr.sin_addr)); + lw_pr_info("client %s connected\n", inet_ntoa(tcp_addr.sin_addr)); while(1) { @@ -163,7 +163,7 @@ static void tcp_send_demo(void *arg) } lw_print("tcp connect success, start to send.\n"); - lw_pr_info("\n\nTarget Port:%d\n\n", tcp_sock.sin_port); + lw_pr_info("\n\nTarget Port:%d\n\n", LWIP_TARGET_PORT); while (cnt --) { diff --git a/APP_Framework/Applications/connection_app/socket_demo/lwip_udp_socket_demo.c b/APP_Framework/Applications/connection_app/socket_demo/lwip_udp_socket_demo.c index b04311f5f..36d49cf4f 100755 --- a/APP_Framework/Applications/connection_app/socket_demo/lwip_udp_socket_demo.c +++ b/APP_Framework/Applications/connection_app/socket_demo/lwip_udp_socket_demo.c @@ -23,11 +23,15 @@ #include "sys_arch.h" #include "lwip/udp.h" #include "lwip/opt.h" +#include +#include "lwip/sys.h" /******************************************************************************* * Definitions ******************************************************************************/ +#define UDP_BUF_SIZE 65536 + /******************************************************************************* * Prototypes ******************************************************************************/ @@ -35,6 +39,7 @@ /******************************************************************************* * Variables ******************************************************************************/ + extern char udp_target[]; static struct udp_pcb *udpecho_raw_pcb; char udp_socket_ip[] = {192, 168, 250, 252}; @@ -42,14 +47,6 @@ char udp_socket_ip[] = {192, 168, 250, 252}; /******************************************************************************* * Code ******************************************************************************/ - -#include -#include "lwip/sys.h" - -#define LWIP_UDP_TASK_STACK 4096 -#define LWIP_UDP_TASK_PRIO 25 -#define UDP_BUF_SIZE 1024 - static void udp_recv_demo(void *arg) { lw_print("udp_recv_demo start.\n"); @@ -63,14 +60,14 @@ static void udp_recv_demo(void *arg) while(1) { recv_buf = (char *)malloc(UDP_BUF_SIZE); - if (recv_buf == NULL) + if(recv_buf == NULL) { lw_print("No memory\n"); goto __exit; } socket_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (socket_fd < 0) + if(socket_fd < 0) { lw_print("Socket error\n"); goto __exit; @@ -81,7 +78,7 @@ static void udp_recv_demo(void *arg) udp_addr.sin_port = htons(LWIP_LOCAL_PORT); memset(&(udp_addr.sin_zero), 0, sizeof(udp_addr.sin_zero)); - if (bind(socket_fd, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr)) == -1) + if(bind(socket_fd, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr)) == -1) { lw_print("Unable to bind\n"); goto __exit; @@ -94,27 +91,24 @@ static void udp_recv_demo(void *arg) { memset(recv_buf, 0, UDP_BUF_SIZE); recv_len = recvfrom(socket_fd, recv_buf, UDP_BUF_SIZE, 0, (struct sockaddr *)&server_addr, &addr_len); - lw_print("Receive from : %s\n", inet_ntoa(server_addr.sin_addr)); - lw_print("Receive data : %s\n\n", recv_buf); + lw_pr_info("Receive from : %s\n", inet_ntoa(server_addr.sin_addr)); + lw_pr_info("Receive data : %s\n\n", recv_buf); sendto(socket_fd, recv_buf, recv_len, 0, (struct sockaddr*)&server_addr, addr_len); } __exit: - if (socket_fd >= 0) + if(socket_fd >= 0) + { closesocket(socket_fd); + } - if (recv_buf) + if(recv_buf) + { free(recv_buf); + } } } -static void udp_recv_demo_thread(void* param) -{ - ETH_BSP_Config(); - lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); - sys_thread_new("udp_recv_demo", udp_recv_demo, NULL, LWIP_UDP_TASK_STACK, LWIP_UDP_TASK_PRIO); -} - void udp_socket_recv_run(int argc, char *argv[]) { int result = 0; @@ -127,7 +121,9 @@ void udp_socket_recv_run(int argc, char *argv[]) sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]); } - sys_thread_new("udp socket send", udp_recv_demo_thread, NULL, 4096, 15); + ETH_BSP_Config(); + lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + sys_thread_new("udp_recv_demo", udp_recv_demo, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO); } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), @@ -144,7 +140,7 @@ static void udp_send_demo(void *arg) memset(send_str, 0, sizeof(send_str)); socket_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (socket_fd < 0) + if(socket_fd < 0) { lw_print("Socket error\n"); goto __exit; @@ -153,10 +149,10 @@ static void udp_send_demo(void *arg) struct sockaddr_in udp_sock; udp_sock.sin_family = AF_INET; udp_sock.sin_port = htons(LWIP_TARGET_PORT); - udp_sock.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(udp_target[0],udp_target[1],udp_target[2],udp_target[3])); + udp_sock.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(udp_target[0], udp_target[1], udp_target[2], udp_target[3])); memset(&(udp_sock.sin_zero), 0, sizeof(udp_sock.sin_zero)); - if (connect(socket_fd, (struct sockaddr *)&udp_sock, sizeof(struct sockaddr))) + if(connect(socket_fd, (struct sockaddr *)&udp_sock, sizeof(struct sockaddr))) { lw_print("Unable to connect\n"); goto __exit; @@ -174,7 +170,7 @@ static void udp_send_demo(void *arg) } __exit: - if (socket_fd >= 0) + if(socket_fd >= 0) { closesocket(socket_fd); } @@ -182,13 +178,6 @@ __exit: return; } -static void udp_send_demo_thread(void* param) -{ - ETH_BSP_Config(); - lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); - sys_thread_new("udp_send_demo", udp_send_demo, NULL, LWIP_UDP_TASK_STACK, LWIP_UDP_TASK_PRIO); -} - void udp_socket_send_run(int argc, char *argv[]) { int result = 0; @@ -201,7 +190,9 @@ void udp_socket_send_run(int argc, char *argv[]) sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]); } - sys_thread_new("udp socket send", udp_send_demo_thread, NULL, 4096, 15); + ETH_BSP_Config(); + lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + sys_thread_new("udp_send_demo", udp_send_demo, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO); } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), diff --git a/APP_Framework/Applications/control_app/opcua_demo/opcua_demo.c b/APP_Framework/Applications/control_app/opcua_demo/opcua_demo.c index 51dd2cecd..f9c2741b5 100755 --- a/APP_Framework/Applications/control_app/opcua_demo/opcua_demo.c +++ b/APP_Framework/Applications/control_app/opcua_demo/opcua_demo.c @@ -31,6 +31,8 @@ #define TCP_LOCAL_PORT 4840 #define UA_URL_SIZE 100 +#define UA_STACK_SIZE 4096 +#define UA_TASK_PRIO 25 /******************************************************************************* * Prototypes @@ -91,7 +93,7 @@ void test_sh_ua_connect(void) int result = 0; pthread_t th_id; pthread_attr_t attr; - sys_thread_new("ua test", test_ua_connect_thr, NULL, 4096, 15); + sys_thread_new("ua test", test_ua_connect_thr, NULL, UA_STACK_SIZE, UA_TASK_PRIO); } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0), @@ -148,7 +150,7 @@ void *test_sh_ua_brower_objects(int argc, char *argv[]) ETH_BSP_Config(); lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip); - sys_thread_new("ua object", test_ua_browser_objects, NULL, 4096, 15); + sys_thread_new("ua object", test_ua_browser_objects, NULL, UA_STACK_SIZE, UA_TASK_PRIO); return NULL; } @@ -202,7 +204,7 @@ void *test_sh_ua_get_info(int argc, char *argv[]) ETH_BSP_Config(); lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip); - sys_thread_new("ua object", test_ua_get_info, NULL, 4096, 15); + sys_thread_new("ua object", test_ua_browser_objects, NULL, UA_STACK_SIZE, UA_TASK_PRIO); return NULL; } diff --git a/APP_Framework/Framework/control/plc/shared/plc.c b/APP_Framework/Framework/control/plc/shared/plc.c index 0ea0c220c..e03d5a24b 100755 --- a/APP_Framework/Framework/control/plc/shared/plc.c +++ b/APP_Framework/Framework/control/plc/shared/plc.c @@ -18,14 +18,20 @@ * @date 2021.12.15 */ + #include "open62541.h" #include "ua_api.h" #include "plc.h" #include "plc_bus.h" #include "plc_dev.h" +#define PLC_BUS_NAME "plc bus" +#define PLC_DRV_NAME "plc driver" struct PlcDevice plc_device; +struct PlcBus plc_bus; +struct PlcDriver plc_drv; + static DoubleLinklistType plcdev_list; @@ -183,3 +189,17 @@ int PlcDeviceAttachToBus(const char *dev_name, const char *bus_name) return EOK; } +void PlcTestInit(void) +{ + PlcBusInit(&plc_bus, PLC_BUS_NAME); + PlcDriverInit(&plc_drv, PLC_DRV_NAME); +} + +void test_plc_bus(int argc, char *argv[]) +{ + PlcTestInit(); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), + plc, test_plc_bus, test PLC); + diff --git a/APP_Framework/Framework/control/plc/shared/plc.h b/APP_Framework/Framework/control/plc/shared/plc.h index c8c8726fc..0c412b836 100755 --- a/APP_Framework/Framework/control/plc/shared/plc.h +++ b/APP_Framework/Framework/control/plc/shared/plc.h @@ -15,9 +15,12 @@ * @brief plc relative definition and structure * @version 1.0 * @author AIIT XUOS Lab - * @date 2021.12.15 + * @date 2022-01-24 */ +#ifndef __PLC_H_ +#define __PLC_H_ + #include "bus.h" #include "xs_klist.h" @@ -78,7 +81,7 @@ enum PlcCtlType { enum PlcIndHybridNet { - //PLC Field Bus + // PLC Field Bus PLC_IND_FIELD_MODBUS_485, PLC_IND_FIELD_PROFIBUS, PLC_IND_FIELD_CANOPEN, @@ -92,7 +95,7 @@ enum PlcIndHybridNet PLC_IND_ENET_SERCOS, PLC_IND_ENET_OPCUA, - //PLC wireless net + // PLC wireless net PLC_IND_WIRELESS }; @@ -112,7 +115,7 @@ struct PlcInterface // identify PLC device struct PlcDevice { - char name[PLC_NAME_SIZE]; /* name of the device */ + char name[PLC_NAME_SIZE]; /* name of the device */ enum PlcCtlType type; /* PLC Control Type */ enum DevState state; enum PlcIndHybridNet net; @@ -125,3 +128,4 @@ struct PlcDevice { DoubleLinklistType link;/* link list node */ }; +#endif diff --git a/APP_Framework/Framework/control/plc/shared/plc_bus.c b/APP_Framework/Framework/control/plc/shared/plc_bus.c index 24697b59e..436c68ec4 100755 --- a/APP_Framework/Framework/control/plc/shared/plc_bus.c +++ b/APP_Framework/Framework/control/plc/shared/plc_bus.c @@ -11,11 +11,11 @@ */ /** -* @file plc_bus.c +* @file bus_plc.c * @brief register plc bus function using bus driver framework -* @version 1.0 +* @version 1.0 * @author AIIT XUOS Lab -* @date 2021-04-24 +* @date 2022-01-24 */ #include "plc_bus.h" @@ -30,7 +30,6 @@ int PlcBusInit(struct PlcBus *plc_bus, const char *bus_name) if (BUS_INSTALL != plc_bus->bus.bus_state) { strncpy(plc_bus->bus.bus_name, bus_name, NAME_NUM_MAX); - plc_bus->bus.bus_type = TYPE_PLC_BUS; plc_bus->bus.bus_state = BUS_INSTALL; plc_bus->bus.private_data = plc_bus->private_data; @@ -41,7 +40,7 @@ int PlcBusInit(struct PlcBus *plc_bus, const char *bus_name) return ret; } } else { - KPrintf("PlcBusInit BusRegister bus has been register state%u\n", plc_bus->bus.bus_state); + KPrintf("PlcBusInit BusRegister bus has been register state%u\n", plc_bus->bus.bus_state); } return ret; @@ -85,7 +84,7 @@ int PlcDriverAttachToBus(const char *drv_name, const char *bus_name) { NULL_PARAM_CHECK(drv_name); NULL_PARAM_CHECK(bus_name); - + x_err_t ret = EOK; struct Bus *bus; @@ -104,6 +103,7 @@ int PlcDriverAttachToBus(const char *drv_name, const char *bus_name) return ERROR; } + if (TYPE_PLC_DRV == driver->driver_type) { ret = DriverRegisterToBus(bus, driver); if (EOK != ret) { diff --git a/APP_Framework/Framework/control/plc/shared/plc_bus.h b/APP_Framework/Framework/control/plc/shared/plc_bus.h index 6bed62b22..0894a6caf 100755 --- a/APP_Framework/Framework/control/plc/shared/plc_bus.h +++ b/APP_Framework/Framework/control/plc/shared/plc_bus.h @@ -13,9 +13,9 @@ /** * @file plc_bus.h * @brief define plc bus and drv function using bus driver framework -* @version 1.0 +* @version 1.0 * @author AIIT XUOS Lab -* @date 2021-04-24 +* @date 2022-01-24 */ #ifndef __PLC_BUS_H_ @@ -30,14 +30,12 @@ extern "C" { struct PlcDriver { struct Driver driver; - uint32 (*configure) (void *drv, struct BusConfigureInfo *configure_info); }; struct PlcBus { struct Bus bus; - void *private_data; }; diff --git a/APP_Framework/Framework/control/plc/shared/plc_dev.c b/APP_Framework/Framework/control/plc/shared/plc_dev.c index da28a5ba0..36dbb1969 100755 --- a/APP_Framework/Framework/control/plc/shared/plc_dev.c +++ b/APP_Framework/Framework/control/plc/shared/plc_dev.c @@ -15,7 +15,7 @@ * @brief register plc dev function using bus driver framework * @version 1.0 * @author AIIT XUOS Lab -* @date 2021-04-24 +* @date 2022-01-24 */ #include "plc_bus.h" @@ -38,6 +38,7 @@ static uint32 PlcHardwareDevOpen(void *dev) return EOK; } + static uint32 PlcHardwareDevClose(void *dev) { NULL_PARAM_CHECK(dev); @@ -47,6 +48,7 @@ static uint32 PlcHardwareDevClose(void *dev) return EOK; } + static uint32 PlcHardwareDevWrite(void *dev, struct BusBlockWriteParam *write_param) { NULL_PARAM_CHECK(dev); @@ -84,12 +86,13 @@ static uint32 PlcHardwareDevRead(void *dev, struct BusBlockReadParam *read_param NULL_PARAM_CHECK(read_param); int ret; + struct PlcHardwareDevice *plc_dev = (struct PlcHardwareDevice *)dev; + struct PlcDataStandard *plc_msg; plc_msg = (struct PlcDataStandard *)x_malloc(sizeof(struct PlcDataStandard)); if (NONE == plc_msg) { - KPrintf("PlcHardwareDevRead x_malloc msg error\n"); x_free(plc_msg); return ERROR; } @@ -214,7 +217,7 @@ int PlcHardwareDevConfigureCs(struct HardwareDev *dev, uint8 plc_chip_select, ui struct PlcDataStandard *msg; msg = (struct PlcDataStandard *)x_malloc(sizeof(struct PlcDataStandard)); - if (NONE == msg) { + if (NONE == msg){ KPrintf("PlcHardwareDevConfigureCs x_malloc msg error\n"); x_free(msg); return ERROR; @@ -228,8 +231,10 @@ int PlcHardwareDevConfigureCs(struct HardwareDev *dev, uint8 plc_chip_select, ui msg->plc_chip_select = plc_chip_select; msg->plc_cs_release = plc_cs_release; + ret = plc_dev->plc_dev_done->dev_write(plc_dev, msg); x_free(msg); return ret; } + diff --git a/APP_Framework/Framework/control/plc/shared/plc_dev.h b/APP_Framework/Framework/control/plc/shared/plc_dev.h index f9eec1ffa..b892d5e5d 100755 --- a/APP_Framework/Framework/control/plc/shared/plc_dev.h +++ b/APP_Framework/Framework/control/plc/shared/plc_dev.h @@ -11,44 +11,44 @@ */ /** -* @file plc_dev.h +* @file dev_plc.h * @brief define plc dev function using bus driver framework * @version 1.0 * @author AIIT XUOS Lab -* @date 2021-04-24 +* @date 2022-01-24 */ -#ifndef __PLC_DEV_H_ -#define __PLC_DEV_H_ +#ifndef DEV_PLC_H +#define DEV_PLC_H #include -#ifdef __cplusplus +#ifdef __cpluspluss extern "C" { #endif -#define PLC_MAX_CLOCK 40000000 +#define PLC_MAX_CLOCK 40000000 #define plc_device_max_num 4 -#define PLC_LINE_CPHA (1<<0) -#define PLC_LINE_CPOL (1<<1) +#define PLC_LINE_CPHA (1 << 0) +#define PLC_LINE_CPOL (1 << 1) -#define PLC_LSB (0<<2) -#define PLC_MSB (1<<2) +#define PLC_LSB (0 << 2) +#define PLC_MSB (1 << 2) -#define PLC_MASTER (0<<3) -#define DEV_PLC_SLAVE (1<<3) +#define PLC_MASTER (0 << 3) +#define DEV_PLC_SLAVE (1 << 3) -#define PLC_MODE_0 (0 | 0) -#define PLC_MODE_1 (0 | PLC_LINE_CPHA) -#define PLC_MODE_2 (PLC_LINE_CPOL | 0) -#define PLC_MODE_3 (PLC_LINE_CPOL | PLC_LINE_CPHA) -#define PLC_MODE_MASK (PLC_LINE_CPHA | PLC_LINE_CPOL | PLC_MSB) +#define PLC_MODE_0 (0 | 0) +#define PLC_MODE_1 (0 | PLC_LINE_CPHA) +#define PLC_MODE_2 (PLC_LINE_CPOL | 0) +#define PLC_MODE_3 (PLC_LINE_CPOL | PLC_LINE_CPHA) +#define PLC_MODE_MASK (PLC_LINE_CPHA | PLC_LINE_CPOL | PLC_MSB) -#define PLC_CS_HIGH (1<<4) -#define PLC_NO_CS (1<<5) -#define PLC_3WIRE (1<<6) -#define PLC_READY (1<<7) +#define PLC_CS_HIGH (1 << 4) +#define PLC_NO_CS (1 << 5) +#define PLC_3WIRE (1 << 6) +#define PLC_READY (1 << 7) struct PlcDataStandard { @@ -70,7 +70,7 @@ struct PlcMasterParam uint8 plc_work_mode;//CPOL CPHA uint8 plc_frame_format;//frame format uint8 plc_data_bit_width;//bit width - uint8 plc_data_endian;//little endian:0,big endian:1 + uint8 plc_data_endian;//little endian 0 : big endian 1 uint32 plc_maxfrequency;//work frequency }; diff --git a/APP_Framework/Framework/control/plc/shared/plc_drv.c b/APP_Framework/Framework/control/plc/shared/plc_drv.c index 2f934fdb8..3dee75a2f 100755 --- a/APP_Framework/Framework/control/plc/shared/plc_drv.c +++ b/APP_Framework/Framework/control/plc/shared/plc_drv.c @@ -11,13 +11,14 @@ */ /** -* @file plc_drv.c +* @file drv_plc.c * @brief register plc drv function using bus driver framework -* @version 1.0 +* @version 1.0 * @author AIIT XUOS Lab -* @date 2021-04-24 +* @date 2022-01-24 */ +#include "transform.h" #include "plc_bus.h" #include "plc_dev.h" @@ -32,7 +33,7 @@ static void PlcDrvLinkInit() DriverType PlcDriverFind(const char *drv_name, enum DriverType_e drv_type) { NULL_PARAM_CHECK(drv_name); - + struct Driver *driver = NONE; DoubleLinklistType *node = NONE; @@ -65,3 +66,4 @@ int PlcDriverRegister(struct Driver *driver) return ret; } + diff --git a/APP_Framework/Framework/transform_layer/nuttx/transform.h b/APP_Framework/Framework/transform_layer/nuttx/transform.h index 7f21e332a..38980b450 100644 --- a/APP_Framework/Framework/transform_layer/nuttx/transform.h +++ b/APP_Framework/Framework/transform_layer/nuttx/transform.h @@ -107,7 +107,7 @@ struct PinDevIrq struct PinParam { int cmd;//< cmd:GPIO_CONFIG_MODE/GPIO_IRQ_REGISTER/GPIO_IRQ_FREE/GPIO_IRQ_DISABLE/GPIO_IRQ_ENABLE - long pin;//< pin number + long pin;//< pin number int mode;//< pin mode: input/output struct PinDevIrq irq_set;//< pin irq set uint64 arg; @@ -170,9 +170,6 @@ int PrivMutexDelete(pthread_mutex_t *p_mutex); int PrivMutexObtain(pthread_mutex_t *p_mutex); int PrivMutexAbandon(pthread_mutex_t *p_mutex); - - - /*********************semaphore**********************/ int PrivSemaphoreCreate(sem_t *sem, int pshared, unsigned int value); diff --git a/Ubiquitous/XiUOS/board/ok1052-c/board.c b/Ubiquitous/XiUOS/board/ok1052-c/board.c index 02fd1cd76..41774ee15 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/board.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/board.c @@ -5,18 +5,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file board.c * @brief relative configure for ok1052-c diff --git a/Ubiquitous/XiUOS/board/ok1052-c/include/board.h b/Ubiquitous/XiUOS/board/ok1052-c/include/board.h index 60d1a97b7..25a95709c 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/include/board.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/include/board.h @@ -5,19 +5,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ - -/* -* Copyright (c) 2020 AIIT XUOS Lab -* XiUOS is licensed under Mulan PSL v2. -* You can use this software according to the terms and conditions of the Mulan PSL v2. -* You may obtain a copy of Mulan PSL v2 at: -* http://license.coscl.org.cn/MulanPSL2 -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -* See the Mulan PSL v2 for more details. -*/ - /** * @file board.h * @brief define imxrt1052-board init configure and start-up function diff --git a/Ubiquitous/XiUOS/board/ok1052-c/include/pin_mux.h b/Ubiquitous/XiUOS/board/ok1052-c/include/pin_mux.h index c5213294a..f45a8ccc0 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/include/pin_mux.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/include/pin_mux.h @@ -8,7 +8,7 @@ /** * @file pin_mux.h * @brief define imxrt1052-board pin configure -* @version 1.0 +* @version 1.0 * @author AIIT XUOS Lab * @date 2021-05-29 */ @@ -71,6 +71,8 @@ void BOARD_InitBootPins(void); * */ void BOARD_InitPins(void); +void BOARD_InitI2C1Pins(void); +void BOARD_InitSPIPins(void); #if defined(__cplusplus) } diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig index a0480d689..282d96d3a 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Kconfig @@ -2,6 +2,7 @@ menuconfig BSP_USING_LPUART bool "Using UART device" default y select RESOURCES_SERIAL + if BSP_USING_LPUART source "$BSP_DIR/third_party_driver/uart/Kconfig" endif @@ -11,6 +12,34 @@ menuconfig BSP_USING_LWIP default n select RESOURCES_LWIP +menuconfig BSP_USING_GPIO + bool "Using GPIO device " + default y + select RESOURCES_PIN + + if BSP_USING_GPIO + source "$BSP_DIR/third_party_driver/gpio/Kconfig" + endif + +menuconfig BSP_USING_I2C + bool "Using I2C device" + default y + select RESOURCES_I2C + + if BSP_USING_I2C + source "$BSP_DIR/third_party_driver/i2c/Kconfig" + endif + +menuconfig BSP_USING_ADC + bool "Using ADC device" + default y + select RESOURCES_ADC + +menuconfig BSP_USING_SPI + bool "Using SPI device" + default y + select RESOURCES_SPI + menuconfig BSP_USING_SEMC bool "Using SEMC device" default y diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile index b55123bc5..84fc9c50f 100644 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/Makefile @@ -8,6 +8,18 @@ ifeq ($(CONFIG_BSP_USING_LWIP),y) SRC_DIR += ethernet endif +ifeq ($(CONFIG_BSP_USING_I2C),y) + SRC_DIR += i2c +endif + +ifeq ($(CONFIG_BSP_USING_ADC),y) + SRC_DIR += adc +endif + +ifeq ($(CONFIG_BSP_USING_SPI),y) + SRC_DIR += spi +endif + ifeq ($(CONFIG_BSP_USING_SEMC),y) SRC_DIR += semc endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/Makefile new file mode 100755 index 000000000..b602cc180 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fsl_adc.c adc_interrupt.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/adc_interrupt.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/adc_interrupt.c new file mode 100755 index 000000000..c51cc2c9c --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/adc_interrupt.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2013 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file adc_interrupt.c + * @brief Demo for ADC function + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022.1.18 + */ + +#include "fsl_debug_console.h" +#include "board.h" +#include "fsl_adc.h" +#include "fsl_common.h" + +#include "pin_mux.h" +#include "clock_config.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define DEMO_ADC_BASE ADC1 +#define DEMO_ADC_IRQn ADC1_IRQn +//#define DEMO_ADC_USER_CHANNEL 0U +#define DEMO_ADC_USER_CHANNEL 3U +#define DEMO_ADC_CHANNEL_GROUP 0U +#define EXAMPLE_ADC_IRQHandler ADC1_IRQHandler + +#define adc_print KPrintf + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +volatile bool g_AdcConversionDoneFlag; +volatile uint32_t g_AdcConversionValue; +volatile uint32_t g_AdcInterruptCounter; +const uint32_t g_Adc_12bitFullRange = 4096U; + +/******************************************************************************* + * Code + ******************************************************************************/ + +//#define ADC_BUS_NAME_1 "adc1" +//#define ADC_DRV_NAME_1 "adc1_drv" +//#define ADC_1_DEVICE_NAME_0 "adc1_dev0" +// +//static struct Bus *adc_bus = NONE; /* I2C bus handle */ +// +//void AdcInit(const char *bus_name, const char *dev_name, const char *drv_name) +//{ +// /* find I2C device and get I2C handle */ +// adc_bus = BusFind(bus_name); +// if (NONE == adc_bus){ +// i2c_print("%s can't find %s bus!\n", __func__, bus_name); +// } +// else{ +// i2c_print("%s find %s bus!\n", __func__, bus_name); +// } +// +// adc_bus->owner_haldev = BusFindDevice(adc_bus, dev_name); +// adc_bus->owner_driver = BusFindDriver(adc_bus, drv_name); +// +// if(adc_bus->match(adc_bus->owner_driver, adc_bus->owner_haldev)){ +// i2c_print("i2c match drv %s %p dev %s %p error\n", drv_name, adc_bus->owner_driver, dev_name, adc_bus->owner_haldev); +// } +// else{ +// i2c_print("HS3000Init successfully!write %p read %p\n", +// adc_bus->owner_haldev->dev_done->write, +// adc_bus->owner_haldev->dev_done->read); +// } +//} +// +//void TestAdcInit(void) +//{ +// AdcInit(ADC_BUS_NAME_1, ADC_1_DEVICE_NAME_0, ADC_DRV_NAME_1); /* init sensor */ +//} + +void EXAMPLE_ADC_IRQHandler(int vector, void *param) +{ + g_AdcConversionDoneFlag = true; + /* Read conversion result to clear the conversion completed flag. */ + g_AdcConversionValue = ADC_GetChannelConversionValue(DEMO_ADC_BASE, DEMO_ADC_CHANNEL_GROUP); + g_AdcInterruptCounter++; +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +DECLARE_HW_IRQ(ADC1_IRQn, EXAMPLE_ADC_IRQHandler, NONE); + +/*! + * @brief Main function + */ +int test_adc(void) +{ + int cnt = 3; + adc_config_t adcConfigStrcut; + adc_channel_config_t adcChannelConfigStruct; + + EnableIRQ(DEMO_ADC_IRQn); + + adc_print("\r\nADC interrupt Example.\r\n"); + + /* + * config->enableAsynchronousClockOutput = true; + * config->enableOverWrite = false; + * config->enableContinuousConversion = false; + * config->enableHighSpeed = false; + * config->enableLowPower = false; + * config->enableLongSample = false; + * config->referenceVoltageSource = kADC_ReferenceVoltageSourceVref; + * config->samplePeriodMode = kADC_SamplePeriod2or12Clocks; + * config->clockSource = kADC_ClockSourceAD; + * config->clockDriver = kADC_ClockDriver1; + * config->resolution = kADC_Resolution12Bit; + */ + ADC_GetDefaultConfig(&adcConfigStrcut); + ADC_Init(DEMO_ADC_BASE, &adcConfigStrcut); +#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) + ADC_EnableHardwareTrigger(DEMO_ADC_BASE, false); +#endif + + /* Do auto hardware calibration. */ + if (kStatus_Success == ADC_DoAutoCalibration(DEMO_ADC_BASE)) + { + adc_print("ADC_DoAntoCalibration() Done.\r\n"); + } + else + { + adc_print("ADC_DoAutoCalibration() Failed.\r\n"); + } + + /* Configure the user channel and interrupt. */ + adcChannelConfigStruct.channelNumber = DEMO_ADC_USER_CHANNEL; + adcChannelConfigStruct.enableInterruptOnConversionCompleted = true; + g_AdcInterruptCounter = 0U; /* Clear the interrupt counter. */ + + adc_print("ADC Full Range: %d\r\n", g_Adc_12bitFullRange); + while (cnt --) + { + adc_print("Press any key to get user channel's ADC value.\r\n"); + getchar(); + g_AdcConversionDoneFlag = false; + /* + When in software trigger mode, each conversion would be launched once calling the "ADC16_ChannelConfigure()" + function, which works like writing a conversion command and executing it. For another channel's conversion, + just to change the "channelNumber" field in channel configuration structure, and call the function + "ADC_ChannelConfigure()"" again. + Also, the "enableInterruptOnConversionCompleted" inside the channel configuration structure is a parameter + for + the conversion command. It takes affect just for the current conversion. If the interrupt is still required + for the following conversion, it is necessary to assert the "enableInterruptOnConversionCompleted" every + time + for each command. + */ + ADC_SetChannelConfig(DEMO_ADC_BASE, DEMO_ADC_CHANNEL_GROUP, &adcChannelConfigStruct); + while (g_AdcConversionDoneFlag == false); + adc_print("ADC Value: %d\r\n", g_AdcConversionValue); + adc_print("ADC Interrupt Counter: %d\r\n", g_AdcInterruptCounter); + } +} + +SHELL_EXPORT_CMD (SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0), + adc, test_adc, ADC test ); + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/fsl_adc.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/fsl_adc.c new file mode 100755 index 000000000..d9b5b6ff1 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/fsl_adc.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_adc.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.adc_12b1msps_sar" +#endif + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Get instance number for ADC module. + * + * @param base ADC peripheral base address + */ +static uint32_t ADC_GetInstance(ADC_Type *base); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Pointers to ADC bases for each instance. */ +static ADC_Type *const s_adcBases[] = ADC_BASE_PTRS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to ADC clocks for each instance. */ +static const clock_ip_name_t s_adcClocks[] = ADC_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/******************************************************************************* + * Code + ******************************************************************************/ +static uint32_t ADC_GetInstance(ADC_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_adcBases); instance++) + { + if (s_adcBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_adcBases)); + + return instance; +} + +/*! + * brief Initialize the ADC module. + * + * param base ADC peripheral base address. + * param config Pointer to "adc_config_t" structure. + */ +void ADC_Init(ADC_Type *base, const adc_config_t *config) +{ + assert(NULL != config); + + uint32_t tmp32; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable the clock. */ + CLOCK_EnableClock(s_adcClocks[ADC_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + /* ADCx_CFG */ + tmp32 = base->CFG & (ADC_CFG_AVGS_MASK | ADC_CFG_ADTRG_MASK); /* Reserve AVGS and ADTRG bits. */ + tmp32 |= ADC_CFG_REFSEL(config->referenceVoltageSource) | ADC_CFG_ADSTS(config->samplePeriodMode) | + ADC_CFG_ADICLK(config->clockSource) | ADC_CFG_ADIV(config->clockDriver) | ADC_CFG_MODE(config->resolution); + if (config->enableOverWrite) + { + tmp32 |= ADC_CFG_OVWREN_MASK; + } + if (config->enableLongSample) + { + tmp32 |= ADC_CFG_ADLSMP_MASK; + } + if (config->enableLowPower) + { + tmp32 |= ADC_CFG_ADLPC_MASK; + } + if (config->enableHighSpeed) + { + tmp32 |= ADC_CFG_ADHSC_MASK; + } + base->CFG = tmp32; + + /* ADCx_GC */ + tmp32 = base->GC & ~(ADC_GC_ADCO_MASK | ADC_GC_ADACKEN_MASK); + if (config->enableContinuousConversion) + { + tmp32 |= ADC_GC_ADCO_MASK; + } + if (config->enableAsynchronousClockOutput) + { + tmp32 |= ADC_GC_ADACKEN_MASK; + } + base->GC = tmp32; +} + +/*! + * brief De-initializes the ADC module. + * + * param base ADC peripheral base address. + */ +void ADC_Deinit(ADC_Type *base) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disable the clock. */ + CLOCK_DisableClock(s_adcClocks[ADC_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Gets an available pre-defined settings for the converter's configuration. + * + * This function initializes the converter configuration structure with available settings. The default values are: + * code + * config->enableAsynchronousClockOutput = true; + * config->enableOverWrite = false; + * config->enableContinuousConversion = false; + * config->enableHighSpeed = false; + * config->enableLowPower = false; + * config->enableLongSample = false; + * config->referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; + * config->samplePeriodMode = kADC_SamplePeriod2or12Clocks; + * config->clockSource = kADC_ClockSourceAD; + * config->clockDriver = kADC_ClockDriver1; + * config->resolution = kADC_Resolution12Bit; + * endcode + * param base ADC peripheral base address. + * param config Pointer to the configuration structure. + */ +void ADC_GetDefaultConfig(adc_config_t *config) +{ + assert(NULL != config); + + /* Initializes the configure structure to zero. */ + memset(config, 0, sizeof(*config)); + + config->enableAsynchronousClockOutput = true; + config->enableOverWrite = false; + config->enableContinuousConversion = false; + config->enableHighSpeed = false; + config->enableLowPower = false; + config->enableLongSample = false; + config->referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; + config->samplePeriodMode = kADC_SamplePeriod2or12Clocks; + config->clockSource = kADC_ClockSourceAD; + config->clockDriver = kADC_ClockDriver1; + config->resolution = kADC_Resolution12Bit; +} + +/*! + * brief Configures the conversion channel. + * + * This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API + * configures the channel while the external trigger source helps to trigger the conversion. + * + * Note that the "Channel Group" has a detailed description. + * To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one + * group of status and control registers, one for each conversion. The channel group parameter indicates which group of + * registers are used, for example channel group 0 is for Group A registers and channel group 1 is for Group B + * registers. The + * channel groups are used in a "ping-pong" approach to control the ADC operation. At any point, only one of + * the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and + * hardware + * trigger modes. Channel groups 1 and greater indicate potentially multiple channel group registers for + * use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual + * about the + * number of SC1n registers (channel groups) specific to this device. None of the channel groups 1 or greater are used + * for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion. + * Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and + * vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a + * conversion aborts the current conversion. + * + * param base ADC peripheral base address. + * param channelGroup Channel group index. + * param config Pointer to the "adc_channel_config_t" structure for the conversion channel. + */ +void ADC_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc_channel_config_t *config) +{ + assert(NULL != config); + assert(channelGroup < FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT); + + uint32_t tmp32; + + tmp32 = ADC_HC_ADCH(config->channelNumber); + if (config->enableInterruptOnConversionCompleted) + { + tmp32 |= ADC_HC_AIEN_MASK; + } + base->HC[channelGroup] = tmp32; +} + +/* + *To complete calibration, the user must follow the below procedure: + * 1. Configure ADC_CFG with actual operating values for maximum accuracy. + * 2. Configure the ADC_GC values along with CAL bit. + * 3. Check the status of CALF bit in ADC_GS and the CAL bit in ADC_GC. + * 4. When CAL bit becomes '0' then check the CALF status and COCO[0] bit status. + */ +/*! + * brief Automates the hardware calibration. + * + * This auto calibration helps to adjust the plus/minus side gain automatically. + * Execute the calibration before using the converter. Note that the software trigger should be used + * during calibration. + * + * param base ADC peripheral base address. + * + * return Execution status. + * retval kStatus_Success Calibration is done successfully. + * retval kStatus_Fail Calibration has failed. + */ +status_t ADC_DoAutoCalibration(ADC_Type *base) +{ + status_t status = kStatus_Success; +#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) + bool bHWTrigger = false; + + /* The calibration would be failed when in hardwar mode. + * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/ + if (0U != (ADC_CFG_ADTRG_MASK & base->CFG)) + { + bHWTrigger = true; + ADC_EnableHardwareTrigger(base, false); + } +#endif + + /* Clear the CALF and launch the calibration. */ + base->GS = ADC_GS_CALF_MASK; /* Clear the CALF. */ + base->GC |= ADC_GC_CAL_MASK; /* Launch the calibration. */ + + /* Check the status of CALF bit in ADC_GS and the CAL bit in ADC_GC. */ + while (0U != (base->GC & ADC_GC_CAL_MASK)) + { + /* Check the CALF when the calibration is active. */ + if (0U != (ADC_GetStatusFlags(base) & kADC_CalibrationFailedFlag)) + { + status = kStatus_Fail; + break; + } + } + + /* When CAL bit becomes '0' then check the CALF status and COCO[0] bit status. */ + if (0U == ADC_GetChannelStatusFlags(base, 0U)) /* Check the COCO[0] bit status. */ + { + status = kStatus_Fail; + } + if (0U != (ADC_GetStatusFlags(base) & kADC_CalibrationFailedFlag)) /* Check the CALF status. */ + { + status = kStatus_Fail; + } + + /* Clear conversion done flag. */ + ADC_GetChannelConversionValue(base, 0U); + +#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) + /* Restore original trigger mode. */ + if (true == bHWTrigger) + { + ADC_EnableHardwareTrigger(base, true); + } +#endif + + return status; +} + +/*! + * brief Set user defined offset. + * + * param base ADC peripheral base address. + * param config Pointer to "adc_offest_config_t" structure. + */ +void ADC_SetOffsetConfig(ADC_Type *base, const adc_offest_config_t *config) +{ + assert(NULL != config); + + uint32_t tmp32; + + tmp32 = ADC_OFS_OFS(config->offsetValue); + if (config->enableSigned) + { + tmp32 |= ADC_OFS_SIGN_MASK; + } + base->OFS = tmp32; +} + +/*! + * brief Configures the hardware compare mode. + * + * The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the + * result + * in the compare range is available. To compare the range, see "adc_hardware_compare_mode_t" or the appopriate + * reference + * manual for more information. + * + * param base ADC peripheral base address. + * param Pointer to "adc_hardware_compare_config_t" structure. + * + */ +void ADC_SetHardwareCompareConfig(ADC_Type *base, const adc_hardware_compare_config_t *config) +{ + uint32_t tmp32; + + tmp32 = base->GC & ~(ADC_GC_ACFE_MASK | ADC_GC_ACFGT_MASK | ADC_GC_ACREN_MASK); + if (NULL == config) /* Pass "NULL" to disable the feature. */ + { + base->GC = tmp32; + return; + } + /* Enable the feature. */ + tmp32 |= ADC_GC_ACFE_MASK; + + /* Select the hardware compare working mode. */ + switch (config->hardwareCompareMode) + { + case kADC_HardwareCompareMode0: + break; + case kADC_HardwareCompareMode1: + tmp32 |= ADC_GC_ACFGT_MASK; + break; + case kADC_HardwareCompareMode2: + tmp32 |= ADC_GC_ACREN_MASK; + break; + case kADC_HardwareCompareMode3: + tmp32 |= ADC_GC_ACFGT_MASK | ADC_GC_ACREN_MASK; + break; + default: + break; + } + base->GC = tmp32; + + /* Load the compare values. */ + tmp32 = ADC_CV_CV1(config->value1) | ADC_CV_CV2(config->value2); + base->CV = tmp32; +} + +/*! + * brief Configures the hardware average mode. + * + * The hardware average mode provides a way to process the conversion result automatically by using hardware. The + * multiple + * conversion results are accumulated and averaged internally making them easier to read. + * + * param base ADC peripheral base address. + * param mode Setting the hardware average mode. See "adc_hardware_average_mode_t". + */ +void ADC_SetHardwareAverageConfig(ADC_Type *base, adc_hardware_average_mode_t mode) +{ + uint32_t tmp32; + + if (mode == kADC_HardwareAverageDiasable) + { + base->GC &= ~ADC_GC_AVGE_MASK; + } + else + { + tmp32 = base->CFG & ~ADC_CFG_AVGS_MASK; + tmp32 |= ADC_CFG_AVGS(mode); + base->CFG = tmp32; + base->GC |= ADC_GC_AVGE_MASK; /* Enable the hardware compare. */ + } +} + +/*! + * brief Clears the converter's status falgs. + * + * param base ADC peripheral base address. + * param mask Mask value for the cleared flags. See "adc_status_flags_t". + */ +void ADC_ClearStatusFlags(ADC_Type *base, uint32_t mask) +{ + uint32_t tmp32 = 0; + + if (0U != (mask & kADC_CalibrationFailedFlag)) + { + tmp32 |= ADC_GS_CALF_MASK; + } + if (0U != (mask & kADC_ConversionActiveFlag)) + { + tmp32 |= ADC_GS_ADACT_MASK; + } + base->GS = tmp32; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/fsl_adc.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/fsl_adc.h new file mode 100755 index 000000000..be4829cb4 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/adc/fsl_adc.h @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_ADC_H_ +#define _FSL_ADC_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup adc_12b1msps_sar + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief ADC driver version */ +#define FSL_ADC_DRIVER_VERSION (MAKE_VERSION(2, 0, 2)) /*!< Version 2.0.2. */ + +/*! + * @brief Converter's status flags. + */ +typedef enum _adc_status_flags +{ + kADC_ConversionActiveFlag = ADC_GS_ADACT_MASK, /*!< Conversion is active,not support w1c. */ + kADC_CalibrationFailedFlag = ADC_GS_CALF_MASK, /*!< Calibration is failed,support w1c. */ + kADC_AsynchronousWakeupInterruptFlag = + ADC_GS_AWKST_MASK, /*!< Asynchronous wakeup interrupt occurred, support w1c. */ +} adc_status_flags_t; + +/*! + * @brief Reference voltage source. + */ +typedef enum _adc_reference_voltage_source +{ + kADC_ReferenceVoltageSourceAlt0 = 0U, /*!< For external pins pair of VrefH and VrefL. */ +} adc_reference_voltage_source_t; + +/*! + * @brief Sample time duration. + */ +typedef enum _adc_sample_period_mode +{ + /* This group of enumeration is for internal use which is related to register setting. */ + kADC_SamplePeriod2or12Clocks = 0U, /*!< Long sample 12 clocks or short sample 2 clocks. */ + kADC_SamplePeriod4or16Clocks = 1U, /*!< Long sample 16 clocks or short sample 4 clocks. */ + kADC_SamplePeriod6or20Clocks = 2U, /*!< Long sample 20 clocks or short sample 6 clocks. */ + kADC_SamplePeriod8or24Clocks = 3U, /*!< Long sample 24 clocks or short sample 8 clocks. */ + /* This group of enumeration is for a public user. */ + /* For long sample mode. */ + kADC_SamplePeriodLong12Clcoks = kADC_SamplePeriod2or12Clocks, /*!< Long sample 12 clocks. */ + kADC_SamplePeriodLong16Clcoks = kADC_SamplePeriod4or16Clocks, /*!< Long sample 16 clocks. */ + kADC_SamplePeriodLong20Clcoks = kADC_SamplePeriod6or20Clocks, /*!< Long sample 20 clocks. */ + kADC_SamplePeriodLong24Clcoks = kADC_SamplePeriod8or24Clocks, /*!< Long sample 24 clocks. */ + /* For short sample mode. */ + kADC_SamplePeriodShort2Clocks = kADC_SamplePeriod2or12Clocks, /*!< Short sample 2 clocks. */ + kADC_SamplePeriodShort4Clocks = kADC_SamplePeriod4or16Clocks, /*!< Short sample 4 clocks. */ + kADC_SamplePeriodShort6Clocks = kADC_SamplePeriod6or20Clocks, /*!< Short sample 6 clocks. */ + kADC_SamplePeriodShort8Clocks = kADC_SamplePeriod8or24Clocks, /*!< Short sample 8 clocks. */ +} adc_sample_period_mode_t; + +/*! + * @brief Clock source. + */ +typedef enum _adc_clock_source +{ + kADC_ClockSourceIPG = 0U, /*!< Select IPG clock to generate ADCK. */ + kADC_ClockSourceIPGDiv2 = 1U, /*!< Select IPG clock divided by 2 to generate ADCK. */ +#if !(defined(FSL_FEATURE_ADC_SUPPORT_ALTCLK_REMOVE) && FSL_FEATURE_ADC_SUPPORT_ALTCLK_REMOVE) + kADC_ClockSourceALT = 2U, /*!< Select alternate clock to generate ADCK. */ +#endif + kADC_ClockSourceAD = 3U, /*!< Select Asynchronous clock to generate ADCK. */ +} adc_clock_source_t; + +/*! + * @brief Clock divider for the converter. + */ +typedef enum _adc_clock_drvier +{ + kADC_ClockDriver1 = 0U, /*!< For divider 1 from the input clock to the module. */ + kADC_ClockDriver2 = 1U, /*!< For divider 2 from the input clock to the module. */ + kADC_ClockDriver4 = 2U, /*!< For divider 4 from the input clock to the module. */ + kADC_ClockDriver8 = 3U, /*!< For divider 8 from the input clock to the module. */ +} adc_clock_driver_t; + +/*! + * @brief Converter's resolution. + */ +typedef enum _adc_resolution +{ + kADC_Resolution8Bit = 0U, /*!< Single End 8-bit resolution. */ + kADC_Resolution10Bit = 1U, /*!< Single End 10-bit resolution. */ + kADC_Resolution12Bit = 2U, /*!< Single End 12-bit resolution. */ +} adc_resolution_t; + +/*! + * @brief Converter hardware compare mode. + */ +typedef enum _adc_hardware_compare_mode +{ + kADC_HardwareCompareMode0 = 0U, /*!< Compare true if the result is less than the value1. */ + kADC_HardwareCompareMode1 = 1U, /*!< Compare true if the result is greater than or equal to value1. */ + kADC_HardwareCompareMode2 = 2U, /*!< Value1 <= Value2, compare true if the result is less than value1 Or + the result is Greater than value2. + Value1 > Value2, compare true if the result is less than value1 And the + result is greater than value2*/ + kADC_HardwareCompareMode3 = 3U, /*!< Value1 <= Value2, compare true if the result is greater than or equal + to value1 And the result is less than or equal to value2. + Value1 > Value2, compare true if the result is greater than or equal to + value1 Or the result is less than or equal to value2. */ +} adc_hardware_compare_mode_t; + +/*! + * @brief Converter hardware average mode. + */ +typedef enum _adc_hardware_average_mode +{ + kADC_HardwareAverageCount4 = 0U, /*!< For hardware average with 4 samples. */ + kADC_HardwareAverageCount8 = 1U, /*!< For hardware average with 8 samples. */ + kADC_HardwareAverageCount16 = 2U, /*!< For hardware average with 16 samples. */ + kADC_HardwareAverageCount32 = 3U, /*!< For hardware average with 32 samples. */ + kADC_HardwareAverageDiasable = 4U, /*!< Disable the hardware average function. */ +} adc_hardware_average_mode_t; + +/*! + * @brief Converter configuration. + */ +typedef struct _adc_config +{ + bool enableOverWrite; /*!< Enable the overwriting. */ + bool enableContinuousConversion; /*!< Enable the continuous conversion mode. */ + bool enableHighSpeed; /*!< Enable the high-speed mode. */ + bool enableLowPower; /*!< Enable the low power mode. */ + bool enableLongSample; /*!< Enable the long sample mode. */ + bool enableAsynchronousClockOutput; /*!< Enable the asynchronous clock output. */ + adc_reference_voltage_source_t referenceVoltageSource; /*!< Select the reference voltage source. */ + adc_sample_period_mode_t samplePeriodMode; /*!< Select the sample period in long sample mode or short mode. */ + adc_clock_source_t clockSource; /*!< Select the input clock source to generate the internal clock ADCK. */ + adc_clock_driver_t clockDriver; /*!< Select the divide ratio used by the ADC to generate the internal clock ADCK. */ + adc_resolution_t resolution; /*!< Select the ADC resolution mode. */ +} adc_config_t; + +/*! + * @brief Converter Offset configuration. + */ +typedef struct _adc_offest_config +{ + bool enableSigned; /*!< if false,The offset value is added with the raw result. + if true,The offset value is subtracted from the raw converted value. */ + uint32_t offsetValue; /*!< User configurable offset value(0-4095). */ +} adc_offest_config_t; + +/*! + * @brief ADC hardware compare configuration. + * + * In kADC_HardwareCompareMode0, compare true if the result is less than the value1. + * In kADC_HardwareCompareMode1, compare true if the result is greater than or equal to value1. + * In kADC_HardwareCompareMode2, Value1 <= Value2, compare true if the result is less than value1 Or the result is + * Greater than value2. + * Value1 > Value2, compare true if the result is less than value1 And the result is + * Greater than value2. + * In kADC_HardwareCompareMode3, Value1 <= Value2, compare true if the result is greater than or equal to value1 And the + * result is less than or equal to value2. + * Value1 > Value2, compare true if the result is greater than or equal to value1 Or the + * result is less than or equal to value2. + */ +typedef struct _adc_hardware_compare_config +{ + adc_hardware_compare_mode_t hardwareCompareMode; /*!< Select the hardware compare mode. + See "adc_hardware_compare_mode_t". */ + uint16_t value1; /*!< Setting value1(0-4095) for hardware compare mode. */ + uint16_t value2; /*!< Setting value2(0-4095) for hardware compare mode. */ +} adc_hardware_compare_config_t; + +/*! + * @brief ADC channel conversion configuration. + */ +typedef struct _adc_channel_config +{ + uint32_t channelNumber; /*!< Setting the conversion channel number. The available range is 0-31. + See channel connection information for each chip in Reference + Manual document. */ + bool enableInterruptOnConversionCompleted; /*!< Generate an interrupt request once the conversion is completed. */ +} adc_channel_config_t; +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Initialization + * @{ + */ + +/*! + * @brief Initialize the ADC module. + * + * @param base ADC peripheral base address. + * @param config Pointer to "adc_config_t" structure. + */ +void ADC_Init(ADC_Type *base, const adc_config_t *config); + +/*! + * @brief De-initializes the ADC module. + * + * @param base ADC peripheral base address. + */ +void ADC_Deinit(ADC_Type *base); + +/*! + * @brief Gets an available pre-defined settings for the converter's configuration. + * + * This function initializes the converter configuration structure with available settings. The default values are: + * @code + * config->enableAsynchronousClockOutput = true; + * config->enableOverWrite = false; + * config->enableContinuousConversion = false; + * config->enableHighSpeed = false; + * config->enableLowPower = false; + * config->enableLongSample = false; + * config->referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0; + * config->samplePeriodMode = kADC_SamplePeriod2or12Clocks; + * config->clockSource = kADC_ClockSourceAD; + * config->clockDriver = kADC_ClockDriver1; + * config->resolution = kADC_Resolution12Bit; + * @endcode + * @param base ADC peripheral base address. + * @param config Pointer to the configuration structure. + */ +void ADC_GetDefaultConfig(adc_config_t *config); + +/*! + * @brief Configures the conversion channel. + * + * This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API + * configures the channel while the external trigger source helps to trigger the conversion. + * + * Note that the "Channel Group" has a detailed description. + * To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one + * group of status and control registers, one for each conversion. The channel group parameter indicates which group of + * registers are used, for example channel group 0 is for Group A registers and channel group 1 is for Group B + * registers. The + * channel groups are used in a "ping-pong" approach to control the ADC operation. At any point, only one of + * the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and + * hardware + * trigger modes. Channel groups 1 and greater indicate potentially multiple channel group registers for + * use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual + * about the + * number of SC1n registers (channel groups) specific to this device. None of the channel groups 1 or greater are used + * for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion. + * Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and + * vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a + * conversion aborts the current conversion. + * + * @param base ADC peripheral base address. + * @param channelGroup Channel group index. + * @param config Pointer to the "adc_channel_config_t" structure for the conversion channel. + */ +void ADC_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc_channel_config_t *config); + +/*! + * @brief Gets the conversion value. + * + * @param base ADC peripheral base address. + * @param channelGroup Channel group index. + * + * @return Conversion value. + */ +static inline uint32_t ADC_GetChannelConversionValue(ADC_Type *base, uint32_t channelGroup) +{ + assert(channelGroup < FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT); + + return base->R[channelGroup]; +} + +/*! + * @brief Gets the status flags of channel. + * + * A conversion is completed when the result of the conversion is transferred into the data + * result registers. (provided the compare function & hardware averaging is disabled), this is + * indicated by the setting of COCOn. If hardware averaging is enabled, COCOn sets only, + * if the last of the selected number of conversions is complete. If the compare function is + * enabled, COCOn sets and conversion result data is transferred only if the compare + * condition is true. If both hardware averaging and compare functions are enabled, then + * COCOn sets only if the last of the selected number of conversions is complete and the + * compare condition is true. + * + * @param base ADC peripheral base address. + * @param channelGroup Channel group index. + * + * @return Status flags of channel.return 0 means COCO flag is 0,return 1 means COCOflag is 1. + */ +static inline uint32_t ADC_GetChannelStatusFlags(ADC_Type *base, uint32_t channelGroup) +{ + assert(channelGroup < FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT); + + /* If flag is set,return 1,otherwise, return 0. */ + return (((base->HS) & (1U << channelGroup)) >> channelGroup); +} + +/*! + * @brief Automates the hardware calibration. + * + * This auto calibration helps to adjust the plus/minus side gain automatically. + * Execute the calibration before using the converter. Note that the software trigger should be used + * during calibration. + * + * @param base ADC peripheral base address. + * + * @return Execution status. + * @retval kStatus_Success Calibration is done successfully. + * @retval kStatus_Fail Calibration has failed. + */ +status_t ADC_DoAutoCalibration(ADC_Type *base); + +/*! + * @brief Set user defined offset. + * + * @param base ADC peripheral base address. + * @param config Pointer to "adc_offest_config_t" structure. + */ +void ADC_SetOffsetConfig(ADC_Type *base, const adc_offest_config_t *config); + +/*! + * @brief Enables generating the DMA trigger when the conversion is complete. + * + * @param base ADC peripheral base address. + * @param enable Switcher of the DMA feature. "true" means enabled, "false" means not enabled. + */ +static inline void ADC_EnableDMA(ADC_Type *base, bool enable) +{ + if (enable) + { + base->GC |= ADC_GC_DMAEN_MASK; + } + else + { + base->GC &= ~ADC_GC_DMAEN_MASK; + } +} + +/*! + * @brief Enables the hardware trigger mode. + * + * @param base ADC peripheral base address. + * @param enable Switcher of the trigger mode. "true" means hardware tirgger mode,"false" means software mode. + */ +#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) +static inline void ADC_EnableHardwareTrigger(ADC_Type *base, bool enable) +{ + if (enable) + { + base->CFG |= ADC_CFG_ADTRG_MASK; + } + else + { + base->CFG &= ~ADC_CFG_ADTRG_MASK; + } +} +#endif + +/*! + * @brief Configures the hardware compare mode. + * + * The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the + * result + * in the compare range is available. To compare the range, see "adc_hardware_compare_mode_t" or the appopriate + * reference + * manual for more information. + * + * @param base ADC peripheral base address. + * @param Pointer to "adc_hardware_compare_config_t" structure. + * + */ +void ADC_SetHardwareCompareConfig(ADC_Type *base, const adc_hardware_compare_config_t *config); + +/*! + * @brief Configures the hardware average mode. + * + * The hardware average mode provides a way to process the conversion result automatically by using hardware. The + * multiple + * conversion results are accumulated and averaged internally making them easier to read. + * + * @param base ADC peripheral base address. + * @param mode Setting the hardware average mode. See "adc_hardware_average_mode_t". + */ +void ADC_SetHardwareAverageConfig(ADC_Type *base, adc_hardware_average_mode_t mode); + +/*! + * @brief Gets the converter's status flags. + * + * @param base ADC peripheral base address. + * + * @return Flags' mask if indicated flags are asserted. See "adc_status_flags_t". + */ +static inline uint32_t ADC_GetStatusFlags(ADC_Type *base) +{ + return base->GS; +} + +/*! + * @brief Clears the converter's status falgs. + * + * @param base ADC peripheral base address. + * @param mask Mask value for the cleared flags. See "adc_status_flags_t". + */ +void ADC_ClearStatusFlags(ADC_Type *base, uint32_t mask); + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_ADC_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_cache.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_cache.c index b601d33d9..29d20b604 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_cache.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_cache.c @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_cache.c * @brief cache drivers @@ -45,9 +33,9 @@ #define L2CACHE_1KBCOVERTOB 1024U #define L2CACHE_SAMLLWAYS_SIZE 16U #define L2CACHE_LOCKDOWN_REGNUM 8 /*!< Lock down register numbers.*/ - /******************************************************************************* - * Prototypes - ******************************************************************************/ +/******************************************************************************* +* Prototypes +******************************************************************************/ /*! * @brief Set for all ways and waiting for the operation finished. * This is provided for all the background operations. diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_clock.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_clock.c index fdb1032da..fae70f54a 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_clock.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_clock.c @@ -5,18 +5,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_clock.c * @brief clock drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_common.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_common.c index 21cd99e4b..e697d0e51 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_common.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/fsl_common.c @@ -7,18 +7,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_common.c * @brief common drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/pin_mux.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/pin_mux.c index 8504b75df..62f19c980 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/pin_mux.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/common/pin_mux.c @@ -639,6 +639,128 @@ BOARD_InitPins: * Description : Configures pin routing and optionally pin electrical features. * * END ****************************************************************************************************************/ + +void BOARD_InitSPIPins(void){ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 is configured as LPUART1_TX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 is configured as LPUART1_RX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_05_FLEXSPIA_DQS, /* GPIO_SD_B1_05 is configured as FLEXSPIA_DQS */ + 1U); /* Software Input On Field: Force input path of pad GPIO_SD_B1_05 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B, /* GPIO_SD_B1_06 is configured as FLEXSPIA_SS0_B */ + 1U); /* Software Input On Field: Force input path of pad GPIO_SD_B1_06 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK, /* GPIO_SD_B1_07 is configured as FLEXSPIA_SCLK */ + 1U); /* Software Input On Field: Force input path of pad GPIO_SD_B1_07 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00, /* GPIO_SD_B1_08 is configured as FLEXSPIA_DATA00 */ + 1U); /* Software Input On Field: Force input path of pad GPIO_SD_B1_08 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01, /* GPIO_SD_B1_09 is configured as FLEXSPIA_DATA01 */ + 1U); /* Software Input On Field: Force input path of pad GPIO_SD_B1_09 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, /* GPIO_SD_B1_10 is configured as FLEXSPIA_DATA02 */ + 1U); /* Software Input On Field: Force input path of pad GPIO_SD_B1_10 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, /* GPIO_SD_B1_11 is configured as FLEXSPIA_DATA03 */ + 1U); /* Software Input On Field: Force input path of pad GPIO_SD_B1_11 */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 PAD functional properties : */ + 0x10B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 PAD functional properties : */ + 0x10B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B1_05_FLEXSPIA_DQS, /* GPIO_SD_B1_05 PAD functional properties : */ + 0x10F1u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/6 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B, /* GPIO_SD_B1_06 PAD functional properties : */ + 0x10F1u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/6 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK, /* GPIO_SD_B1_07 PAD functional properties : */ + 0x10F1u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/6 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00, /* GPIO_SD_B1_08 PAD functional properties : */ + 0x10F1u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/6 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01, /* GPIO_SD_B1_09 PAD functional properties : */ + 0x10F1u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/6 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, /* GPIO_SD_B1_10 PAD functional properties : */ + 0x10F1u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/6 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, /* GPIO_SD_B1_11 PAD functional properties : */ + 0x10F1u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/6 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Disabled */ +} + + void BOARD_InitPins(void) { CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ @@ -848,8 +970,41 @@ void BOARD_InitPins(void) { Pull / Keep Select Field: Pull Pull Up / Down Config. Field: 100K Ohm Pull Up Hyst. Enable Field: Hysteresis Disabled */ + } +void BOARD_InitI2C1Pins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, /* GPIO_AD_B1_00 is configured as LPI2C1_SCL */ + 1U); /* Software Input On Field: Force input path of pad GPIO_AD_B1_00 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, /* GPIO_AD_B1_01 is configured as LPI2C1_SDA */ + 1U); /* Software Input On Field: Force input path of pad GPIO_AD_B1_01 */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, /* GPIO_AD_B1_00 PAD functional properties : */ + 0xD8B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Enabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 22K Ohm Pull Up + Hyst. Enable Field: Hysteresis Disabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, /* GPIO_AD_B1_01 PAD functional properties : */ + 0xD8B0u); /* Slew Rate Field: Slow Slew Rate + Drive Strength Field: R0/6 + Speed Field: medium(100MHz) + Open Drain Enable Field: Open Drain Enabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 22K Ohm Pull Up + Hyst. Enable Field: Hysteresis Disabled */ +} + + /*********************************************************************************************************************** * EOF **********************************************************************************************************************/ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif.c index 40a9e3251..d04c8adb3 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif.c @@ -38,18 +38,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file enet_ethernetif.c * @brief ethernet drivers @@ -90,7 +78,6 @@ * Definitions ******************************************************************************/ - /******************************************************************************* * Code ******************************************************************************/ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif_kinetis.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif_kinetis.c index dd91ce952..fe8f7c3d1 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif_kinetis.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif_kinetis.c @@ -38,18 +38,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file enet_ethernetif_kinetis.c * @brief ethernet drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif_lpc.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif_lpc.c index d851dc709..622fb8b2d 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif_lpc.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif_lpc.c @@ -38,18 +38,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file enet_ethernetif_lpc.c * @brief ethernet drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/fsl_enet.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/fsl_enet.c index a5f14720d..cd73be820 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/fsl_enet.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/fsl_enet.c @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_enet.c * @brief ethernet drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.c index 4edcc9185..7f99f8216 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.c @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_phy.c * @brief phy drivers for ksz8081 diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.h index 4d7b8246d..3f0e905fa 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.h @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_phy.h * @brief phy drivers for ksz8081 diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/Kconfig new file mode 100755 index 000000000..f284f60e3 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/Kconfig @@ -0,0 +1,12 @@ + +config PIN_BUS_NAME + string "pin bus name" + default "pin" + +config PIN_DRIVER_NAME + string "pin driver name" + default "pin_drv" + +config PIN_DEVICE_NAME + string "pin device name" + default "pin_dev" diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/Makefile index 2776af734..a69677383 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/Makefile +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/Makefile @@ -1,3 +1,3 @@ -SRC_FILES := fsl_gpio.c +SRC_FILES := connect_gpio.c fsl_gpio.c include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/connect_gpio.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/connect_gpio.c new file mode 100755 index 000000000..fdc55b4d9 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/gpio/connect_gpio.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2020 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-06 balanceTWK first version + * 2019-04-23 WillianChan Fix GPIO serial number disorder +*/ + +/** +* @file connect_gpio.c +* @brief support gpio function using bus driver framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: connect_gpio.c +Description: support gpio configure and register to bus framework +Others: take RT-Thread v4.0.2/bsp/stm32/libraries/HAL_Drivers/drv_gpio.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: add bus driver framework support for gpio +*************************************************/ + +#include +#include + +#define STM32_PIN_NUMBERS 100 // [48, 64, 100, 144] + +#define ITEM_NUM(items) sizeof(items)/sizeof(items[0]) + +struct PinIndex +{ + int index; + GPIO_Type *gpio; + uint32_t pin; +}; + +struct PinIrq +{ + uint8 port_source; + uint8 pin_source; + enum IRQn irq_exti_channel; + uint32 exti_line; +}; + +static const struct PinIndex pins[] = { + {0, GPIO1, 0}, + {1, GPIO1, 1}, + {2, GPIO1, 2}, + {3, GPIO1, 3}, + {4, GPIO1, 4}, + {5, GPIO1, 5}, + {6, GPIO1, 6}, + {7, GPIO1, 7}, + {8, GPIO1, 8}, + {9, GPIO1, 9}, + {10, GPIO1, 10}, + {11, GPIO1, 11}, + {12, GPIO1, 12}, + {13, GPIO1, 13}, + {14, GPIO1, 14}, + {15, GPIO1, 15}, + {16, GPIO2, 0}, + {17, GPIO2, 1}, + {18, GPIO2, 2}, + {19, GPIO2, 3}, + {20, GPIO2, 4}, + {21, GPIO2, 5}, + {22, GPIO2, 6}, + {23, GPIO2, 7}, + {24, GPIO2, 8}, + {25, GPIO2, 9}, + {26, GPIO2, 10}, + {27, GPIO2, 11}, + {28, GPIO2, 12}, + {29, GPIO2, 13}, + {30, GPIO2, 14}, + {31, GPIO2, 15}, + {32, GPIO3, 0}, + {33, GPIO3, 1}, + {34, GPIO3, 2}, + {35, GPIO3, 3}, + {36, GPIO3, 4}, + {37, GPIO3, 5}, + {38, GPIO3, 6}, + {39, GPIO3, 7}, + {40, GPIO3, 8}, + {41, GPIO3, 9}, + {42, GPIO3, 10}, + {43, GPIO3, 11}, + {44, GPIO3, 12}, + {45, GPIO3, 13}, + {46, GPIO3, 14}, + {47, GPIO3, 15}, + {-1, 0u, -1} +}; + +struct PinIrqHdr pin_irq_hdr_tab[] = {}; + +const struct PinIndex *GetPin(uint8_t pin) +{ + const struct PinIndex *index; + + if (pin < ITEM_NUM(pins)){ + index = &pins[pin]; + if (index->index == -1) + index = NONE; + } + else{ + index = NONE; + } + + return index; +} + +static int32 GpioConfigMode(int mode, const struct PinIndex* index) +{ + gpio_pin_config_t gpio_config; + NULL_PARAM_CHECK(index); + + switch (mode) + { + case GPIO_CFG_OUTPUT: + gpio_config.direction = kGPIO_DigitalOutput; + gpio_config.interruptMode = kGPIO_NoIntmode; + break; + case GPIO_CFG_INPUT: + gpio_config.direction = kGPIO_DigitalInput; + gpio_config.interruptMode = kGPIO_NoIntmode; + break; + case GPIO_CFG_INPUT_PULLUP: + gpio_config.direction = kGPIO_DigitalInput; + gpio_config.interruptMode = kGPIO_IntRisingEdge; + break; + case GPIO_CFG_INPUT_PULLDOWN: + gpio_config.direction = kGPIO_DigitalInput; + gpio_config.interruptMode = kGPIO_IntFallingEdge; + break; + case GPIO_CFG_OUTPUT_OD: + gpio_config.direction = kGPIO_DigitalOutput; + break; + default: + break; + } + GPIO_PinInit(index->gpio, index->pin, &gpio_config); + return EOK; +} + +static __inline int32 Bit2Bitnum(uint32 bit) +{ + for (int i = 0; i < 32; i++){ + if ((1UL << i) == bit){ + return i; + } + } + return -1; +} + +static __inline int32 Bitno2Bit(uint32 bitno) +{ + if (bitno <= 32) { + return 1UL << bitno; + } + else { + return 0; + } +} +static const struct PinIrq *GetPinIrq(uint16_t pin) +{ + static struct PinIrq irq; + const struct PinIndex* index = GetPin(pin); + + if (index == NONE) { + return NONE; + } + + irq.exti_line = index->pin; + irq.pin_source = Bit2Bitnum(index->pin); + irq.port_source = ((uint32_t)index->gpio - GPIO1_BASE) / (GPIO2_BASE - GPIO1_BASE); + switch (irq.pin_source) + { + case 0 : + irq.irq_exti_channel = GPIO1_INT0_IRQn; + break; + case 1 : + irq.irq_exti_channel = GPIO1_INT1_IRQn; + break; + case 2 : + irq.irq_exti_channel = GPIO1_INT2_IRQn; + break; + case 3 : + irq.irq_exti_channel = GPIO1_INT3_IRQn; + break; + case 4 : + irq.irq_exti_channel = GPIO1_INT4_IRQn; + break; + case 5 : + irq.irq_exti_channel = GPIO1_INT5_IRQn; + break; + case 6 : + irq.irq_exti_channel = GPIO1_INT6_IRQn; + break; + case 7 : + irq.irq_exti_channel = GPIO1_INT7_IRQn; + break; + default : + return NONE; + } + + return &irq; +}; +static int32 GpioIrqRegister(int32 pin, int32 mode, void (*hdr)(void *args), void *args) +{ + const struct PinIndex* index = GetPin(pin); + int32 irqindex = -1; + + irqindex = Bit2Bitnum(index->pin); + if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_hdr_tab)) { + return -ENONESYS; + } + + x_base level = CriticalAreaLock(); + if (pin_irq_hdr_tab[irqindex].pin == pin && + pin_irq_hdr_tab[irqindex].hdr == hdr && + pin_irq_hdr_tab[irqindex].mode == mode && + pin_irq_hdr_tab[irqindex].args == args + ) + { + CriticalAreaUnLock(level); + return EOK; + } + if (pin_irq_hdr_tab[irqindex].pin != -1) { + CriticalAreaUnLock(level); + return -EDEV_BUSY; + } + pin_irq_hdr_tab[irqindex].pin = pin; + pin_irq_hdr_tab[irqindex].hdr = hdr; + pin_irq_hdr_tab[irqindex].mode = mode; + pin_irq_hdr_tab[irqindex].args = args; + CriticalAreaUnLock(level); + + return EOK; +} + +static uint32 GpioIrqFree(int32 pin) +{ + const struct PinIndex* index = GetPin(pin); + int32 irqindex = -1; + + irqindex = Bit2Bitnum(index->pin); + if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_hdr_tab)) { + return -ENONESYS; + } + + x_base level = CriticalAreaLock(); + if (pin_irq_hdr_tab[irqindex].pin == -1){ + CriticalAreaUnLock(level); + return EOK; + } + pin_irq_hdr_tab[irqindex].pin = -1; + pin_irq_hdr_tab[irqindex].hdr = NONE; + pin_irq_hdr_tab[irqindex].mode = 0; + pin_irq_hdr_tab[irqindex].args = NONE; + CriticalAreaUnLock(level); + + return EOK; +} + +static int32 GpioIrqEnable(x_base pin) +{ + const struct PinIndex* index = GetPin(pin); + int32 irqindex = -1; + const struct PinIrq *irq; + gpio_pin_config_t gpio_config; + + irqindex = Bit2Bitnum(index->pin); + if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_hdr_tab)){ + return -ENONESYS; + } + x_base level = CriticalAreaLock(); + if (pin_irq_hdr_tab[irqindex].pin == -1) { + CriticalAreaUnLock(level); + return -ENONESYS; + } + + irq = GetPinIrq(pin); + if (irq == NONE){ + CriticalAreaUnLock(level); + return -ENONESYS; + } + + switch (pin_irq_hdr_tab[irqindex].mode) + { + case GPIO_IRQ_EDGE_RISING: + gpio_config.direction = kGPIO_DigitalInput; + gpio_config.interruptMode = kGPIO_IntRisingEdge; + break; + case GPIO_IRQ_EDGE_FALLING: + gpio_config.direction = kGPIO_DigitalInput; + gpio_config.interruptMode = kGPIO_IntFallingEdge; + break; + case GPIO_IRQ_EDGE_BOTH: + gpio_config.direction = kGPIO_DigitalInput; + gpio_config.interruptMode = kGPIO_IntRisingOrFallingEdge; + break; + } + + GPIO_PinInit(index->gpio, index->pin, &gpio_config); + GPIO_PortEnableInterrupts(index->gpio, index->pin); + CriticalAreaUnLock(level); + return EOK; +} + +static int32 GpioIrqDisable(x_base pin) +{ + const struct PinIndex* index = GetPin(pin); + const struct PinIrq *irq; + + irq = GetPinIrq(index->pin); + NULL_PARAM_CHECK(irq); + + GPIO_PortDisableInterrupts(index->gpio, index->pin); + return EOK; +} + +static uint32 Stm32PinConfigure(struct PinParam *param) +{ + NULL_PARAM_CHECK(param); + int ret = EOK; + + const struct PinIndex *index = GetPin(param->pin); + switch(param->cmd) + { + case GPIO_CONFIG_MODE: + GpioConfigMode(param->mode, index); + break; + case GPIO_IRQ_REGISTER: + ret = GpioIrqRegister(param->pin,param->irq_set.irq_mode,param->irq_set.hdr,param->irq_set.args); + break; + case GPIO_IRQ_FREE: + ret = GpioIrqFree(param->pin); + break; + case GPIO_IRQ_ENABLE: + ret = GpioIrqEnable(param->pin); + break; + case GPIO_IRQ_DISABLE: + ret = GpioIrqDisable(param->pin); + break; + default: + ret = -EINVALED; + break; + } + + return ret; +} + +static uint32 Stm32PinInit(void) +{ + static x_bool pin_init_flag = RET_FALSE; + + if (!pin_init_flag) { + pin_init_flag = RET_TRUE; + } + + return EOK; +} + +static uint32 Stm32GpioDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + struct PinParam *param; + + switch (configure_info->configure_cmd) + { + case OPE_INT: + ret = Stm32PinInit(); + break; + case OPE_CFG: + param = (struct PinParam *)configure_info->private_data; + ret = Stm32PinConfigure(param); + break; + default: + break; + } + + return ret; +} + +uint32 Stm32PinWrite(void *dev, struct BusBlockWriteParam *write_param) +{ + NULL_PARAM_CHECK(dev); + NULL_PARAM_CHECK(write_param); + struct PinStat *pinstat = (struct PinStat *)write_param->buffer; + const struct PinIndex* index = GetPin(pinstat->pin); + NULL_PARAM_CHECK(index); + + if (GPIO_LOW == pinstat->val) { + GPIO_PinWrite(index->gpio, index->pin, 0); + } else { + GPIO_PinWrite(index->gpio, index->pin, 1); + } + return EOK; +} + +uint32 Stm32PinRead(void *dev, struct BusBlockReadParam *read_param) +{ + NULL_PARAM_CHECK(dev); + NULL_PARAM_CHECK(read_param); + struct PinStat *pinstat = (struct PinStat *)read_param->buffer; + const struct PinIndex* index = GetPin(pinstat->pin); + NULL_PARAM_CHECK(index); + + if(GPIO_PinRead(index->gpio, index->pin) == GPIO_LOW) { + pinstat->val = GPIO_LOW; + } else { + pinstat->val = GPIO_HIGH; + } + return pinstat->val; +} + +static const struct PinDevDone dev_done = +{ + .open = NONE, + .close = NONE, + .write = Stm32PinWrite, + .read = Stm32PinRead, +}; + +int Stm32HwGpioInit(void) +{ + x_err_t ret = EOK; + + static struct PinBus pin; + + ret = PinBusInit(&pin, PIN_BUS_NAME); + if (ret != EOK) { + KPrintf("gpio bus init error %d\n", ret); + return ERROR; + } + + static struct PinDriver drv; + drv.configure = &Stm32GpioDrvConfigure; + + ret = PinDriverInit(&drv, PIN_DRIVER_NAME, NONE); + if (ret != EOK) { + KPrintf("pin driver init error %d\n", ret); + return ERROR; + } + ret = PinDriverAttachToBus(PIN_DRIVER_NAME, PIN_BUS_NAME); + if (ret != EOK) { + KPrintf("pin driver attach error %d\n", ret); + return ERROR; + } + + static struct PinHardwareDevice dev; + dev.dev_done = &dev_done; + + ret = PinDeviceRegister(&dev, NONE, PIN_DEVICE_NAME); + if (ret != EOK) { + KPrintf("pin device register error %d\n", ret); + return ERROR; + } + ret = PinDeviceAttachToBus(PIN_DEVICE_NAME, PIN_BUS_NAME); + if (ret != EOK) { + KPrintf("pin device register error %d\n", ret); + return ERROR; + } + + return ret; +} + +static __inline void PinIrqHdr(int irqno) +{ + const struct PinIndex* index = GetPin(irqno); + const struct PinIrq *irq; + + irq = GetPinIrq(index->pin); + NULL_PARAM_CHECK(irq); + + GPIO_ClearPinsInterruptFlags(index->gpio, index->pin); + + if (pin_irq_hdr_tab[irqno].hdr){ + pin_irq_hdr_tab[irqno].hdr(pin_irq_hdr_tab[irqno].args); + } +} + +void EXTI0_IRQHandler(int irq_num, void *arg) +{ + PinIrqHdr(0); +} +DECLARE_HW_IRQ(GPIO1_INT0_IRQn, EXTI0_IRQHandler, NONE); + +void EXTI1_IRQHandler(int irq_num, void *arg) +{ + PinIrqHdr(1); +} +DECLARE_HW_IRQ(GPIO1_INT1_IRQn, EXTI1_IRQHandler, NONE); + +void EXTI2_IRQHandler(int irq_num, void *arg) +{ + PinIrqHdr(2); +} +DECLARE_HW_IRQ(GPIO1_INT2_IRQn, EXTI2_IRQHandler, NONE); + +void EXTI3_IRQHandler(int irq_num, void *arg) +{ + PinIrqHdr(3); +} +DECLARE_HW_IRQ(GPIO1_INT3_IRQn, EXTI3_IRQHandler, NONE); + +void EXTI4_IRQHandler(int irq_num, void *arg) +{ + PinIrqHdr(4); +} +DECLARE_HW_IRQ(GPIO1_INT4_IRQn, EXTI4_IRQHandler, NONE); + +void EXTI5_IRQHandler(int irq_num, void *arg) +{ + PinIrqHdr(5); +} +DECLARE_HW_IRQ(GPIO1_INT5_IRQn, EXTI5_IRQHandler, NONE); + +void EXTI6_IRQHandler(int irq_num, void *arg) +{ + PinIrqHdr(6); +} +DECLARE_HW_IRQ(GPIO1_INT6_IRQn, EXTI6_IRQHandler, NONE); + +void EXTI7_IRQHandler(int irq_num, void *arg) +{ + PinIrqHdr(7); +} +DECLARE_HW_IRQ(GPIO1_INT7_IRQn, EXTI7_IRQHandler, NONE); + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/Kconfig b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/Kconfig new file mode 100755 index 000000000..8dec8369f --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/Kconfig @@ -0,0 +1,12 @@ +if BSP_USING_I2C + config I2C_BUS_NAME_1 + string "i2c bus 1 name" + default "i2c1" + config I2C_DRV_NAME_1 + string "i2c bus 1 driver name" + default "i2c1_drv" + config I2C_1_DEVICE_NAME_0 + string "i2c bus 1 device 0 name" + default "i2c1_dev0" +endif + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/Makefile new file mode 100755 index 000000000..3f937865d --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := connect_i2c.c i2c_eeprom.c i2c_eeprom_test.c fsl_lpi2c.c i2c_rtc_rx8010.c i2c_rtc_rx8010_test.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/connect_i2c.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/connect_i2c.c new file mode 100755 index 000000000..c89d01e9e --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/connect_i2c.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2020 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2012-04-25 weety first version + */ + +/** +* @file connect_i2c.c +* @brief support stm32f407-st-discovery-board i2c function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: connect_i2c.c +Description: support stm32f407-st-discovery-board i2c configure and i2c bus register function +Others: take RT-Thread v4.0.2/components/drivers/i2c/i2c-bit-ops.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. support stm32f407-st-discovery-board i2c bit configure, write and read +2. support stm32f407-st-discovery-board i2c bus device and driver register +*************************************************/ + +#include +#include "connect_i2c.h" +#include "bus_serial.h" +#include "i2c_rtc_rx8010.h" +#include "i2c_eeprom.h" + +#ifndef BSP_USING_I2C1 +#define BSP_USING_I2C1 +#endif + +static uint32 I2cWriteData(struct I2cHardwareDevice *i2c_dev, struct I2cDataStandard *msg) +{ + int32 ret; + + if(i2c_dev->i2c_dev_addr == I2C_RTC_ADDR){ + ret = rx8010_set_time(msg->buf); + } else if(i2c_dev->i2c_dev_addr == I2C_EEPROM_ADDR) { + ret = eeprom_write(msg->buf); + } + + return ret; +} + +static uint32 I2cReadData(struct I2cHardwareDevice *i2c_dev, struct I2cDataStandard *msg) +{ + int32 ret; + + if(i2c_dev->i2c_dev_addr == I2C_RTC_ADDR){ + ret = rx8010_get_time(); + } else if(i2c_dev->i2c_dev_addr == I2C_EEPROM_ADDR) { + ret = eeprom_read(msg->buf); + } + return ret; +} + +static uint32 I2cInit(struct I2cDriver *i2c_drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(i2c_drv); + + struct I2cHardwareDevice *i2c_dev = (struct I2cHardwareDevice *)i2c_drv->driver.owner_bus->owner_haldev; + + if (configure_info->private_data) { + i2c_dev->i2c_dev_addr = *((uint16 *)configure_info->private_data); + return EOK; + } + + KPrintf("I2cInit need set i2c dev addr\n"); + return ERROR; +} + +static uint32 I2cDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + struct I2cDriver *i2c_drv = (struct I2cDriver *)drv; + + switch (configure_info->configure_cmd) + { + case OPE_INT: + ret = I2cInit(i2c_drv, configure_info); + break; + default: + break; + } + + return ret; +} + +/*manage the i2c device operations*/ +static const struct I2cDevDone i2c_dev_done = +{ + .dev_open = NONE, + .dev_close = NONE, + .dev_write = I2cWriteData, + .dev_read = I2cReadData, +}; + +/*Init i2c bus*/ +static int BoardI2cBusInit(struct I2cBus *i2c_bus, struct I2cDriver *i2c_driver) +{ + x_err_t ret = EOK; + + /*Init the i2c bus */ + i2c_bus->private_data = (void *)NULL; + ret = I2cBusInit(i2c_bus, I2C_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_i2c_init I2cBusInit error %d\n", ret); + return ERROR; + } + + /*Init the i2c driver*/ + i2c_driver->private_data = (void *)NULL; + ret = I2cDriverInit(i2c_driver, I2C_DRV_NAME_1); + if (EOK != ret) { + KPrintf("board_i2c_init I2cDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the i2c driver to the i2c bus*/ + ret = I2cDriverAttachToBus(I2C_DRV_NAME_1, I2C_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_i2c_init I2cDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the i2c device to the i2c bus*/ +static int BoardI2cDevBend(void) +{ + x_err_t ret = EOK; + static struct I2cHardwareDevice i2c_device0; + memset(&i2c_device0, 0, sizeof(struct I2cHardwareDevice)); + + i2c_device0.i2c_dev_done = &i2c_dev_done; + + ret = I2cDeviceRegister(&i2c_device0, NONE, I2C_1_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("board_i2c_init I2cDeviceInit device %s error %d\n", I2C_1_DEVICE_NAME_0, ret); + return ERROR; + } + + ret = I2cDeviceAttachToBus(I2C_1_DEVICE_NAME_0, I2C_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_i2c_init I2cDeviceAttachToBus device %s error %d\n", I2C_1_DEVICE_NAME_0, ret); + return ERROR; + } + + return ret; +} + +/*BOARD I2C INIT*/ +int Stm32HwI2cInit(void) +{ + static int init_flag = 0; + x_err_t ret = EOK; + + if(init_flag) + { + return ret; + } + init_flag = 1; + + static struct I2cBus i2c_bus; + memset(&i2c_bus, 0, sizeof(struct I2cBus)); + static struct I2cDriver i2c_driver; + memset(&i2c_driver, 0, sizeof(struct I2cDriver)); + +#ifdef BSP_USING_I2C1 + i2c_driver.configure = I2cDrvConfigure; + + ret = BoardI2cBusInit(&i2c_bus, &i2c_driver); + if (EOK != ret) { + KPrintf("board_i2c_Init error ret %u\n", ret); + return ERROR; + } + + ret = BoardI2cDevBend(); + if (EOK != ret) { + KPrintf("board_i2c_Init error ret %u\n", ret); + return ERROR; + } +#endif + + return ret; +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/fsl_lpi2c.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/fsl_lpi2c.c new file mode 100755 index 000000000..01149c65d --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/fsl_lpi2c.c @@ -0,0 +1,2245 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_lpi2c.h" +#include +#include + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.lpi2c" +#endif + +/*! @brief Common sets of flags used by the driver. */ +enum _lpi2c_flag_constants +{ + /*! All flags which are cleared by the driver upon starting a transfer. */ + kMasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | + kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag | + kLPI2C_MasterDataMatchFlag, + + /*! IRQ sources enabled by the non-blocking transactional API. */ + kMasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag | + kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag | + kLPI2C_MasterFifoErrFlag, + + /*! Errors to check for. */ + kMasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | + kLPI2C_MasterPinLowTimeoutFlag, + + /*! All flags which are cleared by the driver upon starting a transfer. */ + kSlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag | + kLPI2C_SlaveFifoErrFlag, + + /*! IRQ sources enabled by the non-blocking transactional API. */ + kSlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | + kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag | + kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag, + + /*! Errors to check for. */ + kSlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag, +}; + +/* ! @brief LPI2C master fifo commands. */ +enum _lpi2c_master_fifo_cmd +{ + kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */ + kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */ + kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */ + kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */ +}; + +/*! + * @brief Default watermark values. + * + * The default watermarks are set to zero. + */ +enum _lpi2c_default_watermarks +{ + kDefaultTxWatermark = 0, + kDefaultRxWatermark = 0, +}; + +/*! @brief States for the state machine used by transactional APIs. */ +enum _lpi2c_transfer_states +{ + kIdleState = 0, + kSendCommandState, + kIssueReadCommandState, + kTransferDataState, + kStopState, + kWaitForCompletionState, +}; + +/*! @brief Typedef for master interrupt handler. */ +typedef void (*lpi2c_master_isr_t)(LPI2C_Type *base, lpi2c_master_handle_t *handle); + +/*! @brief Typedef for slave interrupt handler. */ +typedef void (*lpi2c_slave_isr_t)(LPI2C_Type *base, lpi2c_slave_handle_t *handle); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/* Not static so it can be used from fsl_lpi2c_edma.c. */ +uint32_t LPI2C_GetInstance(LPI2C_Type *base); + +static uint32_t LPI2C_GetCyclesForWidth(uint32_t sourceClock_Hz, + uint32_t width_ns, + uint32_t maxCycles, + uint32_t prescaler); + +static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base); + +static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone); + +static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle); + +static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags); + +static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief Array to map LPI2C instance number to base pointer. */ +static LPI2C_Type *const kLpi2cBases[] = LPI2C_BASE_PTRS; + +/*! @brief Array to map LPI2C instance number to IRQ number. */ +static IRQn_Type const kLpi2cIrqs[] = LPI2C_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Array to map LPI2C instance number to clock gate enum. */ +static clock_ip_name_t const kLpi2cClocks[] = LPI2C_CLOCKS; + +#if defined(LPI2C_PERIPH_CLOCKS) +/*! @brief Array to map LPI2C instance number to pheripheral clock gate enum. */ +static const clock_ip_name_t kLpi2cPeriphClocks[] = LPI2C_PERIPH_CLOCKS; +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointer to master IRQ handler for each instance. */ +static lpi2c_master_isr_t s_lpi2cMasterIsr; + +/*! @brief Pointers to master handles for each instance. */ +static lpi2c_master_handle_t *s_lpi2cMasterHandle[ARRAY_SIZE(kLpi2cBases)]; + +/*! @brief Pointer to slave IRQ handler for each instance. */ +static lpi2c_slave_isr_t s_lpi2cSlaveIsr; + +/*! @brief Pointers to slave handles for each instance. */ +static lpi2c_slave_handle_t *s_lpi2cSlaveHandle[ARRAY_SIZE(kLpi2cBases)]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Returns an instance number given a base address. + * + * If an invalid base address is passed, debug builds will assert. Release builds will just return + * instance number 0. + * + * @param base The LPI2C peripheral base address. + * @return LPI2C instance number starting from 0. + */ +uint32_t LPI2C_GetInstance(LPI2C_Type *base) +{ + uint32_t instance; + for (instance = 0; instance < ARRAY_SIZE(kLpi2cBases); ++instance) + { + if (kLpi2cBases[instance] == base) + { + return instance; + } + } + + assert(false); + return 0; +} + +/*! + * @brief Computes a cycle count for a given time in nanoseconds. + * @param sourceClock_Hz LPI2C functional clock frequency in Hertz. + * @param width_ns Desired with in nanoseconds. + * @param maxCycles Maximum cycle count, determined by the number of bits wide the cycle count field is. + * @param prescaler LPI2C prescaler setting. Pass 1 if the prescaler should not be used, as for slave glitch widths. + */ +static uint32_t LPI2C_GetCyclesForWidth(uint32_t sourceClock_Hz, + uint32_t width_ns, + uint32_t maxCycles, + uint32_t prescaler) +{ + assert(sourceClock_Hz > 0); + assert(prescaler > 0); + + uint32_t busCycle_ns = 1000000 / (sourceClock_Hz / prescaler / 1000); + uint32_t cycles = 0; + + /* Search for the cycle count just below the desired glitch width. */ + while ((((cycles + 1) * busCycle_ns) < width_ns) && (cycles + 1 < maxCycles)) + { + ++cycles; + } + + /* If we end up with zero cycles, then set the filter to a single cycle unless the */ + /* bus clock is greater than 10x the desired glitch width. */ + if ((cycles == 0) && (busCycle_ns <= (width_ns * 10))) + { + cycles = 1; + } + + return cycles; +} + +/*! + * @brief Convert provided flags to status code, and clear any errors if present. + * @param base The LPI2C peripheral base address. + * @param status Current status flags value that will be checked. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_PinLowTimeout + * @retval #kStatus_LPI2C_ArbitrationLost + * @retval #kStatus_LPI2C_Nak + * @retval #kStatus_LPI2C_FifoError + */ +/* Not static so it can be used from fsl_lpi2c_edma.c. */ +status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status) +{ + status_t result = kStatus_Success; + + /* Check for error. These errors cause a stop to automatically be sent. We must */ + /* clear the errors before a new transfer can start. */ + status &= kMasterErrorFlags; + if (status) + { + /* Select the correct error code. Ordered by severity, with bus issues first. */ + if (status & kLPI2C_MasterPinLowTimeoutFlag) + { + result = kStatus_LPI2C_PinLowTimeout; + } + else if (status & kLPI2C_MasterArbitrationLostFlag) + { + result = kStatus_LPI2C_ArbitrationLost; + } + else if (status & kLPI2C_MasterNackDetectFlag) + { + result = kStatus_LPI2C_Nak; + } + else if (status & kLPI2C_MasterFifoErrFlag) + { + result = kStatus_LPI2C_FifoError; + } + else + { + assert(false); + } + + /* Clear the flags. */ + LPI2C_MasterClearStatusFlags(base, status); + + /* Reset fifos. These flags clear automatically. */ + base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK; + } + + return result; +} + +/*! + * @brief Wait until there is room in the tx fifo. + * @param base The LPI2C peripheral base address. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_PinLowTimeout + * @retval #kStatus_LPI2C_ArbitrationLost + * @retval #kStatus_LPI2C_Nak + * @retval #kStatus_LPI2C_FifoError + */ +static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base) +{ + uint32_t status; + size_t txCount; + size_t txFifoSize = FSL_FEATURE_LPI2C_FIFO_SIZEn(base); + +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + do + { + status_t result; + + /* Get the number of words in the tx fifo and compute empty slots. */ + LPI2C_MasterGetFifoCounts(base, NULL, &txCount); + txCount = txFifoSize - txCount; + + /* Check for error flags. */ + status = LPI2C_MasterGetStatusFlags(base); + result = LPI2C_MasterCheckAndClearError(base, status); + if (result) + { + return result; + } +#if LPI2C_WAIT_TIMEOUT + } while ((!txCount) && (--waitTimes)); + + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#else + } while (!txCount); +#endif + + return kStatus_Success; +} + +/*! + * @brief Make sure the bus isn't already busy. + * + * A busy bus is allowed if we are the one driving it. + * + * @param base The LPI2C peripheral base address. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_Busy + */ +/* Not static so it can be used from fsl_lpi2c_edma.c. */ +status_t LPI2C_CheckForBusyBus(LPI2C_Type *base) +{ + uint32_t status = LPI2C_MasterGetStatusFlags(base); + if ((status & kLPI2C_MasterBusBusyFlag) && (!(status & kLPI2C_MasterBusyFlag))) + { + return kStatus_LPI2C_Busy; + } + + return kStatus_Success; +} + +/*! + * brief Provides a default configuration for the LPI2C master peripheral. + * + * This function provides the following default configuration for the LPI2C master peripheral: + * code + * masterConfig->enableMaster = true; + * masterConfig->debugEnable = false; + * masterConfig->ignoreAck = false; + * masterConfig->pinConfig = kLPI2C_2PinOpenDrain; + * masterConfig->baudRate_Hz = 100000U; + * masterConfig->busIdleTimeout_ns = 0; + * masterConfig->pinLowTimeout_ns = 0; + * masterConfig->sdaGlitchFilterWidth_ns = 0; + * masterConfig->sclGlitchFilterWidth_ns = 0; + * masterConfig->hostRequest.enable = false; + * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin; + * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh; + * endcode + * + * After calling this function, you can override any settings in order to customize the configuration, + * prior to initializing the master driver with LPI2C_MasterInit(). + * + * param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t. + */ +void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig) +{ + /* Initializes the configure structure to zero. */ + memset(masterConfig, 0, sizeof(*masterConfig)); + + masterConfig->enableMaster = true; + masterConfig->debugEnable = false; + masterConfig->enableDoze = true; + masterConfig->ignoreAck = false; + masterConfig->pinConfig = kLPI2C_2PinOpenDrain; + masterConfig->baudRate_Hz = 100000U; + masterConfig->busIdleTimeout_ns = 0; + masterConfig->pinLowTimeout_ns = 0; + masterConfig->sdaGlitchFilterWidth_ns = 0; + masterConfig->sclGlitchFilterWidth_ns = 0; + masterConfig->hostRequest.enable = false; + masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin; + masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh; +} + +/*! + * brief Initializes the LPI2C master peripheral. + * + * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user + * provided configuration. A software reset is performed prior to configuration. + * + * param base The LPI2C peripheral base address. + * param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of + * defaults + * that you can override. + * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors, + * filter widths, and timeout periods. + */ +void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz) +{ + uint32_t prescaler; + uint32_t cycles; + uint32_t cfgr2; + uint32_t value; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPI2C_GetInstance(base); + + /* Ungate the clock. */ + CLOCK_EnableClock(kLpi2cClocks[instance]); +#if defined(LPI2C_PERIPH_CLOCKS) + /* Ungate the functional clock in initialize function. */ + CLOCK_EnableClock(kLpi2cPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset peripheral before configuring it. */ + LPI2C_MasterReset(base); + + /* Doze bit: 0 is enable, 1 is disable */ + base->MCR = LPI2C_MCR_DBGEN(masterConfig->debugEnable) | LPI2C_MCR_DOZEN(!(masterConfig->enableDoze)); + + /* host request */ + value = base->MCFGR0; + value &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK | LPI2C_MCFGR0_HRSEL_MASK)); + value |= LPI2C_MCFGR0_HREN(masterConfig->hostRequest.enable) | + LPI2C_MCFGR0_HRPOL(masterConfig->hostRequest.polarity) | + LPI2C_MCFGR0_HRSEL(masterConfig->hostRequest.source); + base->MCFGR0 = value; + + /* pin config and ignore ack */ + value = base->MCFGR1; + value &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK); + value |= LPI2C_MCFGR1_PINCFG(masterConfig->pinConfig); + value |= LPI2C_MCFGR1_IGNACK(masterConfig->ignoreAck); + base->MCFGR1 = value; + + LPI2C_MasterSetWatermarks(base, kDefaultTxWatermark, kDefaultRxWatermark); + + LPI2C_MasterSetBaudRate(base, sourceClock_Hz, masterConfig->baudRate_Hz); + + /* Configure glitch filters and bus idle and pin low timeouts. */ + prescaler = (base->MCFGR1 & LPI2C_MCFGR1_PRESCALE_MASK) >> LPI2C_MCFGR1_PRESCALE_SHIFT; + cfgr2 = base->MCFGR2; + if (masterConfig->busIdleTimeout_ns) + { + cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->busIdleTimeout_ns, + (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler); + cfgr2 &= ~LPI2C_MCFGR2_BUSIDLE_MASK; + cfgr2 |= LPI2C_MCFGR2_BUSIDLE(cycles); + } + if (masterConfig->sdaGlitchFilterWidth_ns) + { + cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sdaGlitchFilterWidth_ns, + (LPI2C_MCFGR2_FILTSDA_MASK >> LPI2C_MCFGR2_FILTSDA_SHIFT), 1); + cfgr2 &= ~LPI2C_MCFGR2_FILTSDA_MASK; + cfgr2 |= LPI2C_MCFGR2_FILTSDA(cycles); + } + if (masterConfig->sclGlitchFilterWidth_ns) + { + cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sclGlitchFilterWidth_ns, + (LPI2C_MCFGR2_FILTSCL_MASK >> LPI2C_MCFGR2_FILTSCL_SHIFT), 1); + cfgr2 &= ~LPI2C_MCFGR2_FILTSCL_MASK; + cfgr2 |= LPI2C_MCFGR2_FILTSCL(cycles); + } + base->MCFGR2 = cfgr2; + if (masterConfig->pinLowTimeout_ns) + { + cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->pinLowTimeout_ns / 256, + (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler); + base->MCFGR3 = (base->MCFGR3 & ~LPI2C_MCFGR3_PINLOW_MASK) | LPI2C_MCFGR3_PINLOW(cycles); + } + + LPI2C_MasterEnable(base, masterConfig->enableMaster); +} + +/*! + * brief Deinitializes the LPI2C master peripheral. + * + * This function disables the LPI2C master peripheral and gates the clock. It also performs a software + * reset to restore the peripheral to reset conditions. + * + * param base The LPI2C peripheral base address. + */ +void LPI2C_MasterDeinit(LPI2C_Type *base) +{ + /* Restore to reset state. */ + LPI2C_MasterReset(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPI2C_GetInstance(base); + + /* Gate clock. */ + CLOCK_DisableClock(kLpi2cClocks[instance]); +#if defined(LPI2C_PERIPH_CLOCKS) + /* Gate the functional clock. */ + CLOCK_DisableClock(kLpi2cPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Configures LPI2C master data match feature. + * + * param base The LPI2C peripheral base address. + * param config Settings for the data match feature. + */ +void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *config) +{ + /* Disable master mode. */ + bool wasEnabled = (base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT; + LPI2C_MasterEnable(base, false); + + base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_MATCFG_MASK) | LPI2C_MCFGR1_MATCFG(config->matchMode); + base->MCFGR0 = (base->MCFGR0 & ~LPI2C_MCFGR0_RDMO_MASK) | LPI2C_MCFGR0_RDMO(config->rxDataMatchOnly); + base->MDMR = LPI2C_MDMR_MATCH0(config->match0) | LPI2C_MDMR_MATCH1(config->match1); + + /* Restore master mode. */ + if (wasEnabled) + { + LPI2C_MasterEnable(base, true); + } +} + +/*! + * brief Sets the I2C bus frequency for master transactions. + * + * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud + * rate. Do not call this function during a transfer, or the transfer is aborted. + * + * note Please note that the second parameter is the clock frequency of LPI2C module, the third + * parameter means user configured bus baudrate, this implementation is different from other I2C drivers + * which use baudrate configuration as second parameter and source clock frequency as third parameter. + * + * param base The LPI2C peripheral base address. + * param sourceClock_Hz LPI2C functional clock frequency in Hertz. + * param baudRate_Hz Requested bus frequency in Hertz. + */ +void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz) +{ + uint32_t prescale = 0; + uint32_t bestPre = 0; + uint32_t bestClkHi = 0; + uint32_t absError = 0; + uint32_t bestError = 0xffffffffu; + uint32_t value; + uint32_t clkHiCycle; + uint32_t computedRate; + int i; + bool wasEnabled; + + /* Disable master mode. */ + wasEnabled = (base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT; + LPI2C_MasterEnable(base, false); + + /* Baud rate = (sourceClock_Hz/2^prescale)/(CLKLO+1+CLKHI+1 + ROUNDDOWN((2+FILTSCL)/2^prescale) */ + /* Assume CLKLO = 2*CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2. */ + for (prescale = 1; (prescale <= 128) && (bestError != 0); prescale = 2 * prescale) + { + for (clkHiCycle = 1; clkHiCycle < 32; clkHiCycle++) + { + if (clkHiCycle == 1) + { + computedRate = (sourceClock_Hz / prescale) / (1 + 3 + 2 + 2 / prescale); + } + else + { + computedRate = (sourceClock_Hz / prescale) / (3 * clkHiCycle + 2 + 2 / prescale); + } + + absError = baudRate_Hz > computedRate ? baudRate_Hz - computedRate : computedRate - baudRate_Hz; + + if (absError < bestError) + { + bestPre = prescale; + bestClkHi = clkHiCycle; + bestError = absError; + + /* If the error is 0, then we can stop searching because we won't find a better match. */ + if (absError == 0) + { + break; + } + } + } + } + + /* Standard, fast, fast mode plus and ultra-fast transfers. */ + value = LPI2C_MCCR0_CLKHI(bestClkHi); + + if (bestClkHi < 2) + { + value |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) | LPI2C_MCCR0_DATAVD(1); + } + else + { + value |= LPI2C_MCCR0_CLKLO(2 * bestClkHi) | LPI2C_MCCR0_SETHOLD(bestClkHi) | LPI2C_MCCR0_DATAVD(bestClkHi / 2); + } + + base->MCCR0 = value; + + for (i = 0; i < 8; i++) + { + if (bestPre == (1U << i)) + { + bestPre = i; + break; + } + } + base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_PRESCALE_MASK) | LPI2C_MCFGR1_PRESCALE(bestPre); + + /* Restore master mode. */ + if (wasEnabled) + { + LPI2C_MasterEnable(base, true); + } +} + +/*! + * brief Sends a START signal and slave address on the I2C bus. + * + * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure + * that another master is not occupying the bus. Then a START signal is transmitted, followed by the + * 7-bit address specified in the a address parameter. Note that this function does not actually wait + * until the START and address are successfully sent on the bus before returning. + * + * param base The LPI2C peripheral base address. + * param address 7-bit slave device address, in bits [6:0]. + * param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set + * the R/w bit (bit 0) in the transmitted slave address. + * retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + */ +status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir) +{ + /* Return an error if the bus is already in use not by us. */ + status_t result = LPI2C_CheckForBusyBus(base); + if (result) + { + return result; + } + + /* Clear all flags. */ + LPI2C_MasterClearStatusFlags(base, kMasterClearFlags); + + /* Turn off auto-stop option. */ + base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; + + /* Wait until there is room in the fifo. */ + result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Issue start command. */ + base->MTDR = kStartCmd | (((uint32_t)address << 1U) | (uint32_t)dir); + + return kStatus_Success; +} + +/*! + * brief Sends a STOP signal on the I2C bus. + * + * This function does not return until the STOP signal is seen on the bus, or an error occurs. + * + * param base The LPI2C peripheral base address. + * retval #kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterStop(LPI2C_Type *base) +{ + /* Wait until there is room in the fifo. */ + status_t result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Send the STOP signal */ + base->MTDR = kStopCmd; + +/* Wait for the stop detected flag to set, indicating the transfer has completed on the bus. */ +/* Also check for errors while waiting. */ +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + +#if LPI2C_WAIT_TIMEOUT + while ((result == kStatus_Success) && (--waitTimes)) +#else + while (result == kStatus_Success) +#endif + { + uint32_t status = LPI2C_MasterGetStatusFlags(base); + + /* Check for error flags. */ + result = LPI2C_MasterCheckAndClearError(base, status); + + /* Check if the stop was sent successfully. */ + if ((status & kLPI2C_MasterStopDetectFlag) && (status & kLPI2C_MasterTxReadyFlag)) + { + LPI2C_MasterClearStatusFlags(base, kLPI2C_MasterStopDetectFlag); + break; + } + } + +#if LPI2C_WAIT_TIMEOUT + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#endif + + return result; +} + +/*! + * brief Performs a polling receive transfer on the I2C bus. + * + * param base The LPI2C peripheral base address. + * param rxBuff The pointer to the data to be transferred. + * param rxSize The length in bytes of the data to be transferred. + * retval #kStatus_Success Data was received successfully. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize) +{ + status_t result; + uint8_t *buf; + + assert(rxBuff); + + /* Handle empty read. */ + if (!rxSize) + { + return kStatus_Success; + } + + /* Wait until there is room in the command fifo. */ + result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Issue command to receive data. */ + base->MTDR = kRxDataCmd | LPI2C_MTDR_DATA(rxSize - 1); + +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + + /* Receive data */ + buf = (uint8_t *)rxBuff; + while (rxSize--) + { + /* Read LPI2C receive fifo register. The register includes a flag to indicate whether */ + /* the FIFO is empty, so we can both get the data and check if we need to keep reading */ + /* using a single register read. */ + uint32_t value; + do + { + /* Check for errors. */ + result = LPI2C_MasterCheckAndClearError(base, LPI2C_MasterGetStatusFlags(base)); + if (result) + { + return result; + } + + value = base->MRDR; +#if LPI2C_WAIT_TIMEOUT + } while ((value & LPI2C_MRDR_RXEMPTY_MASK) && (--waitTimes)); + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#else + } while (value & LPI2C_MRDR_RXEMPTY_MASK); +#endif + + *buf++ = value & LPI2C_MRDR_DATA_MASK; + } + + return kStatus_Success; +} + +/*! + * brief Performs a polling send transfer on the I2C bus. + * + * Sends up to a txSize number of bytes to the previously addressed slave device. The slave may + * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this + * function returns #kStatus_LPI2C_Nak. + * + * param base The LPI2C peripheral base address. + * param txBuff The pointer to the data to be transferred. + * param txSize The length in bytes of the data to be transferred. + * retval #kStatus_Success Data was sent successfully. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * retval #kStatus_LPI2C_FifoError FIFO under run or over run. + * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize) +{ + uint8_t *buf = (uint8_t *)txBuff; + + assert(txBuff); + + /* Send data buffer */ + while (txSize--) + { + /* Wait until there is room in the fifo. This also checks for errors. */ + status_t result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Write byte into LPI2C master data register. */ + base->MTDR = *buf++; + } + + return kStatus_Success; +} + +/*! + * brief Performs a master polling transfer on the I2C bus. + * + * note The API does not return until the transfer succeeds or fails due + * to error happens during transfer. + * + * param base The LPI2C peripheral base address. + * param transfer Pointer to the transfer structure. + * retval #kStatus_Success Data was received successfully. + * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer) +{ + status_t result = kStatus_Success; + uint16_t commandBuffer[7]; + uint32_t cmdCount = 0; + + assert(transfer); + assert(transfer->subaddressSize <= sizeof(transfer->subaddress)); + + /* Return an error if the bus is already in use not by us. */ + result = LPI2C_CheckForBusyBus(base); + if (result) + { + return result; + } + + /* Clear all flags. */ + LPI2C_MasterClearStatusFlags(base, kMasterClearFlags); + + /* Turn off auto-stop option. */ + base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; + + lpi2c_direction_t direction = transfer->subaddressSize ? kLPI2C_Write : transfer->direction; + if (!(transfer->flags & kLPI2C_TransferNoStartFlag)) + { + commandBuffer[cmdCount++] = + (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)direction); + } + + /* Subaddress, MSB first. */ + if (transfer->subaddressSize) + { + uint32_t subaddressRemaining = transfer->subaddressSize; + while (subaddressRemaining--) + { + uint8_t subaddressByte = (transfer->subaddress >> (8 * subaddressRemaining)) & 0xff; + commandBuffer[cmdCount++] = subaddressByte; + } + } + + /* Reads need special handling. */ + if ((transfer->dataSize) && (transfer->direction == kLPI2C_Read)) + { + /* Need to send repeated start if switching directions to read. */ + if (direction == kLPI2C_Write) + { + commandBuffer[cmdCount++] = + (uint16_t)kStartCmd | + (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read); + } + } + + /* Send command buffer */ + uint32_t index = 0; + while (cmdCount--) + { + /* Wait until there is room in the fifo. This also checks for errors. */ + result = LPI2C_MasterWaitForTxReady(base); + if (result) + { + return result; + } + + /* Write byte into LPI2C master data register. */ + base->MTDR = commandBuffer[index]; + index++; + } + + /* Transmit data. */ + if ((transfer->direction == kLPI2C_Write) && (transfer->dataSize > 0)) + { + /* Send Data. */ + result = LPI2C_MasterSend(base, transfer->data, transfer->dataSize); + } + + /* Receive Data. */ + if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > 0)) + { + result = LPI2C_MasterReceive(base, transfer->data, transfer->dataSize); + } + + if (result) + { + return result; + } + + if ((transfer->flags & kLPI2C_TransferNoStopFlag) == 0) + { + result = LPI2C_MasterStop(base); + } + + return result; +} + +/*! + * brief Creates a new handle for the LPI2C master non-blocking APIs. + * + * The creation of a handle is for use with the non-blocking APIs. Once a handle + * is created, there is not a corresponding destroy handle. If the user wants to + * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called. + * + * + * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice + * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to + * enable the associated INTMUX IRQ in application. + * + * param base The LPI2C peripheral base address. + * param[out] handle Pointer to the LPI2C master driver handle. + * param callback User provided pointer to the asynchronous callback function. + * param userData User provided pointer to the application callback data. + */ +void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base, + lpi2c_master_handle_t *handle, + lpi2c_master_transfer_callback_t callback, + void *userData) +{ + uint32_t instance; + + assert(handle); + + /* Clear out the handle. */ + memset(handle, 0, sizeof(*handle)); + + /* Look up instance number */ + instance = LPI2C_GetInstance(base); + + /* Save base and instance. */ + handle->completionCallback = callback; + handle->userData = userData; + + /* Save this handle for IRQ use. */ + s_lpi2cMasterHandle[instance] = handle; + + /* Set irq handler. */ + s_lpi2cMasterIsr = LPI2C_MasterTransferHandleIRQ; + + /* Clear internal IRQ enables and enable NVIC IRQ. */ + LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags); + + /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC. + In some cases the LPI2C IRQ is configured through INTMUX, user needs to enable + INTMUX IRQ in application code. */ + EnableIRQ(kLpi2cIrqs[instance]); +} + +/*! + * @brief Execute states until FIFOs are exhausted. + * @param handle Master nonblocking driver handle. + * @param[out] isDone Set to true if the transfer has completed. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_PinLowTimeout + * @retval #kStatus_LPI2C_ArbitrationLost + * @retval #kStatus_LPI2C_Nak + * @retval #kStatus_LPI2C_FifoError + */ +static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone) +{ + uint32_t status; + status_t result = kStatus_Success; + lpi2c_master_transfer_t *xfer; + size_t txCount; + size_t rxCount; + size_t txFifoSize = FSL_FEATURE_LPI2C_FIFO_SIZEn(base); + bool state_complete = false; + + /* Set default isDone return value. */ + *isDone = false; + + /* Check for errors. */ + status = LPI2C_MasterGetStatusFlags(base); + result = LPI2C_MasterCheckAndClearError(base, status); + if (result) + { + return result; + } + + /* Get pointer to private data. */ + xfer = &handle->transfer; + + /* Get fifo counts and compute room in tx fifo. */ + LPI2C_MasterGetFifoCounts(base, &rxCount, &txCount); + txCount = txFifoSize - txCount; + + while (!state_complete) + { + /* Execute the state. */ + switch (handle->state) + { + case kSendCommandState: + { + /* Make sure there is room in the tx fifo for the next command. */ + if (!txCount--) + { + state_complete = true; + break; + } + + /* Issue command. buf is a uint8_t* pointing at the uint16 command array. */ + base->MTDR = *(uint16_t *)handle->buf; + handle->buf += sizeof(uint16_t); + + /* Count down until all commands are sent. */ + if (--handle->remainingBytes == 0) + { + /* Choose next state and set up buffer pointer and count. */ + if (xfer->dataSize) + { + /* Either a send or receive transfer is next. */ + handle->state = kTransferDataState; + handle->buf = (uint8_t *)xfer->data; + handle->remainingBytes = xfer->dataSize; + if (xfer->direction == kLPI2C_Read) + { + /* Disable TX interrupt */ + LPI2C_MasterDisableInterrupts(base, kLPI2C_MasterTxReadyFlag); + } + } + else + { + /* No transfer, so move to stop state. */ + handle->state = kStopState; + } + } + break; + } + + case kIssueReadCommandState: + /* Make sure there is room in the tx fifo for the read command. */ + if (!txCount--) + { + state_complete = true; + break; + } + + base->MTDR = kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1); + + /* Move to transfer state. */ + handle->state = kTransferDataState; + if (xfer->direction == kLPI2C_Read) + { + /* Disable TX interrupt */ + LPI2C_MasterDisableInterrupts(base, kLPI2C_MasterTxReadyFlag); + } + break; + + case kTransferDataState: + if (xfer->direction == kLPI2C_Write) + { + /* Make sure there is room in the tx fifo. */ + if (!txCount--) + { + state_complete = true; + break; + } + + /* Put byte to send in fifo. */ + base->MTDR = *(handle->buf)++; + } + else + { + /* XXX handle receive sizes > 256, use kIssueReadCommandState */ + /* Make sure there is data in the rx fifo. */ + if (!rxCount--) + { + state_complete = true; + break; + } + + /* Read byte from fifo. */ + *(handle->buf)++ = base->MRDR & LPI2C_MRDR_DATA_MASK; + } + + /* Move to stop when the transfer is done. */ + if (--handle->remainingBytes == 0) + { + if (xfer->direction == kLPI2C_Write) + { + state_complete = true; + } + handle->state = kStopState; + } + break; + + case kStopState: + /* Only issue a stop transition if the caller requested it. */ + if ((xfer->flags & kLPI2C_TransferNoStopFlag) == 0) + { + /* Make sure there is room in the tx fifo for the stop command. */ + if (!txCount--) + { + state_complete = true; + break; + } + + base->MTDR = kStopCmd; + } + else + { + /* Caller doesn't want to send a stop, so we're done now. */ + *isDone = true; + state_complete = true; + break; + } + handle->state = kWaitForCompletionState; + break; + + case kWaitForCompletionState: + /* We stay in this state until the stop state is detected. */ + if (status & kLPI2C_MasterStopDetectFlag) + { + *isDone = true; + } + state_complete = true; + break; + default: + assert(false); + break; + } + } + return result; +} + +/*! + * @brief Prepares the transfer state machine and fills in the command buffer. + * @param handle Master nonblocking driver handle. + */ +static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle) +{ + lpi2c_master_transfer_t *xfer = &handle->transfer; + + /* Handle no start option. */ + if (xfer->flags & kLPI2C_TransferNoStartFlag) + { + if (xfer->direction == kLPI2C_Read) + { + /* Need to issue read command first. */ + handle->state = kIssueReadCommandState; + } + else + { + /* Start immediately in the data transfer state. */ + handle->state = kTransferDataState; + } + + handle->buf = (uint8_t *)xfer->data; + handle->remainingBytes = xfer->dataSize; + } + else + { + uint16_t *cmd = (uint16_t *)&handle->commandBuffer; + uint32_t cmdCount = 0; + + /* Initial direction depends on whether a subaddress was provided, and of course the actual */ + /* data transfer direction. */ + lpi2c_direction_t direction = xfer->subaddressSize ? kLPI2C_Write : xfer->direction; + + /* Start command. */ + cmd[cmdCount++] = + (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction); + + /* Subaddress, MSB first. */ + if (xfer->subaddressSize) + { + uint32_t subaddressRemaining = xfer->subaddressSize; + while (subaddressRemaining--) + { + uint8_t subaddressByte = (xfer->subaddress >> (8 * subaddressRemaining)) & 0xff; + cmd[cmdCount++] = subaddressByte; + } + } + + /* Reads need special handling. */ + if ((xfer->dataSize) && (xfer->direction == kLPI2C_Read)) + { + /* Need to send repeated start if switching directions to read. */ + if (direction == kLPI2C_Write) + { + cmd[cmdCount++] = (uint16_t)kStartCmd | + (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read); + } + + /* Read command. */ + cmd[cmdCount++] = kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1); + } + + /* Set up state machine for transferring the commands. */ + handle->state = kSendCommandState; + handle->remainingBytes = cmdCount; + handle->buf = (uint8_t *)&handle->commandBuffer; + } +} + +/*! + * brief Performs a non-blocking transaction on the I2C bus. + * + * param base The LPI2C peripheral base address. + * param handle Pointer to the LPI2C master driver handle. + * param transfer The pointer to the transfer descriptor. + * retval #kStatus_Success The transaction was started successfully. + * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking + * transaction is already in progress. + */ +status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base, + lpi2c_master_handle_t *handle, + lpi2c_master_transfer_t *transfer) +{ + status_t result; + + assert(handle); + assert(transfer); + assert(transfer->subaddressSize <= sizeof(transfer->subaddress)); + + /* Return busy if another transaction is in progress. */ + if (handle->state != kIdleState) + { + return kStatus_LPI2C_Busy; + } + + /* Return an error if the bus is already in use not by us. */ + result = LPI2C_CheckForBusyBus(base); + if (result) + { + return result; + } + + /* Disable LPI2C IRQ sources while we configure stuff. */ + LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags); + + /* Save transfer into handle. */ + handle->transfer = *transfer; + + /* Generate commands to send. */ + LPI2C_InitTransferStateMachine(handle); + + /* Clear all flags. */ + LPI2C_MasterClearStatusFlags(base, kMasterClearFlags); + + /* Turn off auto-stop option. */ + base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK; + + /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */ + LPI2C_MasterEnableInterrupts(base, kMasterIrqFlags); + + return result; +} + +/*! + * brief Returns number of bytes transferred so far. + * param base The LPI2C peripheral base address. + * param handle Pointer to the LPI2C master driver handle. + * param[out] count Number of bytes transferred so far by the non-blocking transaction. + * retval #kStatus_Success + * retval #kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. + */ +status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count) +{ + assert(handle); + + if (!count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (handle->state == kIdleState) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + uint8_t state; + uint16_t remainingBytes; + uint32_t dataSize; + + /* Cache some fields with IRQs disabled. This ensures all field values */ + /* are synchronized with each other during an ongoing transfer. */ + uint32_t irqs = LPI2C_MasterGetEnabledInterrupts(base); + LPI2C_MasterDisableInterrupts(base, irqs); + state = handle->state; + remainingBytes = handle->remainingBytes; + dataSize = handle->transfer.dataSize; + LPI2C_MasterEnableInterrupts(base, irqs); + + /* Get transfer count based on current transfer state. */ + switch (state) + { + case kIdleState: + case kSendCommandState: + case kIssueReadCommandState: /* XXX return correct value for this state when >256 reads are supported */ + *count = 0; + break; + + case kTransferDataState: + *count = dataSize - remainingBytes; + break; + + case kStopState: + case kWaitForCompletionState: + default: + *count = dataSize; + break; + } + + return kStatus_Success; +} + +/*! + * brief Terminates a non-blocking LPI2C master transmission early. + * + * note It is not safe to call this function from an IRQ handler that has a higher priority than the + * LPI2C peripheral's IRQ priority. + * + * param base The LPI2C peripheral base address. + * param handle Pointer to the LPI2C master driver handle. + * retval #kStatus_Success A transaction was successfully aborted. + * retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress. + */ +void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle) +{ + if (handle->state != kIdleState) + { + /* Disable internal IRQ enables. */ + LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags); + + /* Reset fifos. */ + base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK; + + /* Send a stop command to finalize the transfer. */ + base->MTDR = kStopCmd; + + /* Reset handle. */ + handle->state = kIdleState; + } +} + +/*! + * brief Reusable routine to handle master interrupts. + * note This function does not need to be called unless you are reimplementing the + * nonblocking API's interrupt handler routines to add special functionality. + * param base The LPI2C peripheral base address. + * param handle Pointer to the LPI2C master driver handle. + */ +void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, lpi2c_master_handle_t *handle) +{ + bool isDone; + status_t result; + + /* Don't do anything if we don't have a valid handle. */ + if (!handle) + { + return; + } + + if (handle->state == kIdleState) + { + return; + } + + result = LPI2C_RunTransferStateMachine(base, handle, &isDone); + + if (isDone || (result != kStatus_Success)) + { + /* XXX need to handle data that may be in rx fifo below watermark level? */ + + /* XXX handle error, terminate xfer */ + + /* Disable internal IRQ enables. */ + LPI2C_MasterDisableInterrupts(base, kMasterIrqFlags); + + /* Set handle to idle state. */ + handle->state = kIdleState; + + /* Invoke callback. */ + if (handle->completionCallback) + { + handle->completionCallback(base, handle, result, handle->userData); + } + } +} + +/*! + * brief Provides a default configuration for the LPI2C slave peripheral. + * + * This function provides the following default configuration for the LPI2C slave peripheral: + * code + * slaveConfig->enableSlave = true; + * slaveConfig->address0 = 0U; + * slaveConfig->address1 = 0U; + * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0; + * slaveConfig->filterDozeEnable = true; + * slaveConfig->filterEnable = true; + * slaveConfig->enableGeneralCall = false; + * slaveConfig->sclStall.enableAck = false; + * slaveConfig->sclStall.enableTx = true; + * slaveConfig->sclStall.enableRx = true; + * slaveConfig->sclStall.enableAddress = true; + * slaveConfig->ignoreAck = false; + * slaveConfig->enableReceivedAddressRead = false; + * slaveConfig->sdaGlitchFilterWidth_ns = 0; + * slaveConfig->sclGlitchFilterWidth_ns = 0; + * slaveConfig->dataValidDelay_ns = 0; + * slaveConfig->clockHoldTime_ns = 0; + * endcode + * + * After calling this function, override any settings to customize the configuration, + * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the a + * address0 member of the configuration structure with the desired slave address. + * + * param[out] slaveConfig User provided configuration structure that is set to default values. Refer to + * #lpi2c_slave_config_t. + */ +void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig) +{ + /* Initializes the configure structure to zero. */ + memset(slaveConfig, 0, sizeof(*slaveConfig)); + + slaveConfig->enableSlave = true; + slaveConfig->address0 = 0U; + slaveConfig->address1 = 0U; + slaveConfig->addressMatchMode = kLPI2C_MatchAddress0; + slaveConfig->filterDozeEnable = true; + slaveConfig->filterEnable = true; + slaveConfig->enableGeneralCall = false; + slaveConfig->sclStall.enableAck = false; + slaveConfig->sclStall.enableTx = true; + slaveConfig->sclStall.enableRx = true; + slaveConfig->sclStall.enableAddress = false; + slaveConfig->ignoreAck = false; + slaveConfig->enableReceivedAddressRead = false; + slaveConfig->sdaGlitchFilterWidth_ns = 0; /* TODO determine default width values */ + slaveConfig->sclGlitchFilterWidth_ns = 0; + slaveConfig->dataValidDelay_ns = 0; + slaveConfig->clockHoldTime_ns = 0; +} + +/*! + * brief Initializes the LPI2C slave peripheral. + * + * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user + * provided configuration. + * + * param base The LPI2C peripheral base address. + * param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults + * that you can override. + * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths, + * data valid delay, and clock hold time. + */ +void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPI2C_GetInstance(base); + + /* Ungate the clock. */ + CLOCK_EnableClock(kLpi2cClocks[instance]); +#if defined(LPI2C_PERIPH_CLOCKS) + /* Ungate the functional clock in initialize function. */ + CLOCK_EnableClock(kLpi2cPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Restore to reset conditions. */ + LPI2C_SlaveReset(base); + + /* Configure peripheral. */ + base->SAMR = LPI2C_SAMR_ADDR0(slaveConfig->address0) | LPI2C_SAMR_ADDR1(slaveConfig->address1); + + base->SCFGR1 = + LPI2C_SCFGR1_ADDRCFG(slaveConfig->addressMatchMode) | LPI2C_SCFGR1_IGNACK(slaveConfig->ignoreAck) | + LPI2C_SCFGR1_RXCFG(slaveConfig->enableReceivedAddressRead) | LPI2C_SCFGR1_GCEN(slaveConfig->enableGeneralCall) | + LPI2C_SCFGR1_ACKSTALL(slaveConfig->sclStall.enableAck) | LPI2C_SCFGR1_TXDSTALL(slaveConfig->sclStall.enableTx) | + LPI2C_SCFGR1_RXSTALL(slaveConfig->sclStall.enableRx) | + LPI2C_SCFGR1_ADRSTALL(slaveConfig->sclStall.enableAddress); + + base->SCFGR2 = + LPI2C_SCFGR2_FILTSDA(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sdaGlitchFilterWidth_ns, + (LPI2C_SCFGR2_FILTSDA_MASK >> LPI2C_SCFGR2_FILTSDA_SHIFT), 1)) | + LPI2C_SCFGR2_FILTSCL(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sclGlitchFilterWidth_ns, + (LPI2C_SCFGR2_FILTSCL_MASK >> LPI2C_SCFGR2_FILTSCL_SHIFT), 1)) | + LPI2C_SCFGR2_DATAVD(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->dataValidDelay_ns, + (LPI2C_SCFGR2_DATAVD_MASK >> LPI2C_SCFGR2_DATAVD_SHIFT), 1)) | + LPI2C_SCFGR2_CLKHOLD(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->clockHoldTime_ns, + (LPI2C_SCFGR2_CLKHOLD_MASK >> LPI2C_SCFGR2_CLKHOLD_SHIFT), 1)); + + /* Save SCR to last so we don't enable slave until it is configured */ + base->SCR = LPI2C_SCR_FILTDZ(slaveConfig->filterDozeEnable) | LPI2C_SCR_FILTEN(slaveConfig->filterEnable) | + LPI2C_SCR_SEN(slaveConfig->enableSlave); +} + +/*! + * brief Deinitializes the LPI2C slave peripheral. + * + * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software + * reset to restore the peripheral to reset conditions. + * + * param base The LPI2C peripheral base address. + */ +void LPI2C_SlaveDeinit(LPI2C_Type *base) +{ + LPI2C_SlaveReset(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPI2C_GetInstance(base); + + /* Gate the clock. */ + CLOCK_DisableClock(kLpi2cClocks[instance]); + +#if defined(LPI2C_PERIPH_CLOCKS) + /* Gate the functional clock. */ + CLOCK_DisableClock(kLpi2cPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * @brief Convert provided flags to status code, and clear any errors if present. + * @param base The LPI2C peripheral base address. + * @param status Current status flags value that will be checked. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_BitError + * @retval #kStatus_LPI2C_FifoError + */ +static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags) +{ + status_t result = kStatus_Success; + + flags &= kSlaveErrorFlags; + if (flags) + { + if (flags & kLPI2C_SlaveBitErrFlag) + { + result = kStatus_LPI2C_BitError; + } + else if (flags & kLPI2C_SlaveFifoErrFlag) + { + result = kStatus_LPI2C_FifoError; + } + else + { + assert(false); + } + + /* Clear the errors. */ + LPI2C_SlaveClearStatusFlags(base, flags); + } + + return result; +} + +/*! + * brief Performs a polling send transfer on the I2C bus. + * + * param base The LPI2C peripheral base address. + * param txBuff The pointer to the data to be transferred. + * param txSize The length in bytes of the data to be transferred. + * param[out] actualTxSize + * return Error or success status returned by API. + */ +status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize) +{ + uint8_t *buf = (uint8_t *)txBuff; + size_t remaining = txSize; + + assert(txBuff); + +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + + /* Clear stop flag. */ + LPI2C_SlaveClearStatusFlags(base, kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag); + + while (remaining) + { + uint32_t flags; + status_t result; + + /* Wait until we can transmit. */ + do + { + /* Check for errors */ + flags = LPI2C_SlaveGetStatusFlags(base); + result = LPI2C_SlaveCheckAndClearError(base, flags); + if (result) + { + if (actualTxSize) + { + *actualTxSize = txSize - remaining; + } + return result; + } +#if LPI2C_WAIT_TIMEOUT + } while ( + (!(flags & (kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag))) && + (--waitTimes)); + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#else + } while ( + !(flags & (kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag))); +#endif + + /* Send a byte. */ + if (flags & kLPI2C_SlaveTxReadyFlag) + { + base->STDR = *buf++; + --remaining; + } + + /* Exit loop if we see a stop or restart in transfer*/ + if ((flags & (kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag)) && (remaining != 0U)) + { + LPI2C_SlaveClearStatusFlags(base, kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag); + break; + } + } + + if (actualTxSize) + { + *actualTxSize = txSize - remaining; + } + + return kStatus_Success; +} + +/*! + * brief Performs a polling receive transfer on the I2C bus. + * + * param base The LPI2C peripheral base address. + * param rxBuff The pointer to the data to be transferred. + * param rxSize The length in bytes of the data to be transferred. + * param[out] actualRxSize + * return Error or success status returned by API. + */ +status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize) +{ + uint8_t *buf = (uint8_t *)rxBuff; + size_t remaining = rxSize; + + assert(rxBuff); + +#if LPI2C_WAIT_TIMEOUT + uint32_t waitTimes = LPI2C_WAIT_TIMEOUT; +#endif + + /* Clear stop flag. */ + LPI2C_SlaveClearStatusFlags(base, kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag); + + while (remaining) + { + uint32_t flags; + status_t result; + + /* Wait until we can receive. */ + do + { + /* Check for errors */ + flags = LPI2C_SlaveGetStatusFlags(base); + result = LPI2C_SlaveCheckAndClearError(base, flags); + if (result) + { + if (actualRxSize) + { + *actualRxSize = rxSize - remaining; + } + return result; + } +#if LPI2C_WAIT_TIMEOUT + } while ( + (!(flags & (kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag))) && + (--waitTimes)); + if (waitTimes == 0) + { + return kStatus_LPI2C_Timeout; + } +#else + } while ( + !(flags & (kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag))); +#endif + + /* Receive a byte. */ + if (flags & kLPI2C_SlaveRxReadyFlag) + { + *buf++ = base->SRDR & LPI2C_SRDR_DATA_MASK; + --remaining; + } + + /* Exit loop if we see a stop or restart */ + if ((flags & (kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag)) && (remaining != 0U)) + { + LPI2C_SlaveClearStatusFlags(base, kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveRepeatedStartDetectFlag); + break; + } + } + + if (actualRxSize) + { + *actualRxSize = rxSize - remaining; + } + + return kStatus_Success; +} + +/*! + * brief Creates a new handle for the LPI2C slave non-blocking APIs. + * + * The creation of a handle is for use with the non-blocking APIs. Once a handle + * is created, there is not a corresponding destroy handle. If the user wants to + * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called. + * + * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice + * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to + * enable the associated INTMUX IRQ in application. + + * param base The LPI2C peripheral base address. + * param[out] handle Pointer to the LPI2C slave driver handle. + * param callback User provided pointer to the asynchronous callback function. + * param userData User provided pointer to the application callback data. + */ +void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base, + lpi2c_slave_handle_t *handle, + lpi2c_slave_transfer_callback_t callback, + void *userData) +{ + uint32_t instance; + + assert(handle); + + /* Clear out the handle. */ + memset(handle, 0, sizeof(*handle)); + + /* Look up instance number */ + instance = LPI2C_GetInstance(base); + + /* Save base and instance. */ + handle->callback = callback; + handle->userData = userData; + + /* Save this handle for IRQ use. */ + s_lpi2cSlaveHandle[instance] = handle; + + /* Set irq handler. */ + s_lpi2cSlaveIsr = LPI2C_SlaveTransferHandleIRQ; + + /* Clear internal IRQ enables and enable NVIC IRQ. */ + LPI2C_SlaveDisableInterrupts(base, kSlaveIrqFlags); + EnableIRQ(kLpi2cIrqs[instance]); + + /* Nack by default. */ + base->STAR = LPI2C_STAR_TXNACK_MASK; +} + +/*! + * brief Starts accepting slave transfers. + * + * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing + * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the + * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked + * from the interrupt context. + * + * The set of events received by the callback is customizable. To do so, set the a eventMask parameter to + * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive. + * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need + * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and + * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as + * a convenient way to enable all events. + * + * param base The LPI2C peripheral base address. + * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + * param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify + * which events to send to the callback. Other accepted values are 0 to get a default set of + * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events. + * + * retval #kStatus_Success Slave transfers were successfully started. + * retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle. + */ +status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask) +{ + uint32_t status; + + assert(handle); + + /* Return busy if another transaction is in progress. */ + if (handle->isBusy) + { + return kStatus_LPI2C_Busy; + } + + /* Return an error if the bus is already in use not by us. */ + status = LPI2C_SlaveGetStatusFlags(base); + if ((status & kLPI2C_SlaveBusBusyFlag) && (!(status & kLPI2C_SlaveBusyFlag))) + { + return kStatus_LPI2C_Busy; + } + + /* Disable LPI2C IRQ sources while we configure stuff. */ + LPI2C_SlaveDisableInterrupts(base, kSlaveIrqFlags); + + /* Clear transfer in handle. */ + memset(&handle->transfer, 0, sizeof(handle->transfer)); + + /* Record that we're busy. */ + handle->isBusy = true; + + /* Set up event mask. tx and rx are always enabled. */ + handle->eventMask = eventMask | kLPI2C_SlaveTransmitEvent | kLPI2C_SlaveReceiveEvent; + + /* Ack by default. */ + base->STAR = 0; + + /* Clear all flags. */ + LPI2C_SlaveClearStatusFlags(base, kSlaveClearFlags); + + /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */ + LPI2C_SlaveEnableInterrupts(base, kSlaveIrqFlags); + + return kStatus_Success; +} + +/*! + * brief Gets the slave transfer status during a non-blocking transfer. + * param base The LPI2C peripheral base address. + * param handle Pointer to i2c_slave_handle_t structure. + * param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not + * required. + * retval #kStatus_Success + * retval #kStatus_NoTransferInProgress + */ +status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count) +{ + assert(handle); + + if (!count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (!handle->isBusy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + /* For an active transfer, just return the count from the handle. */ + *count = handle->transferredCount; + + return kStatus_Success; +} + +/*! + * brief Aborts the slave non-blocking transfers. + * note This API could be called at any time to stop slave for handling the bus events. + * param base The LPI2C peripheral base address. + * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + * retval #kStatus_Success + * retval #kStatus_LPI2C_Idle + */ +void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle) +{ + assert(handle); + + /* Return idle if no transaction is in progress. */ + if (handle->isBusy) + { + /* Disable LPI2C IRQ sources. */ + LPI2C_SlaveDisableInterrupts(base, kSlaveIrqFlags); + + /* Nack by default. */ + base->STAR = LPI2C_STAR_TXNACK_MASK; + + /* Reset transfer info. */ + memset(&handle->transfer, 0, sizeof(handle->transfer)); + + /* We're no longer busy. */ + handle->isBusy = false; + } +} + +/*! + * brief Reusable routine to handle slave interrupts. + * note This function does not need to be called unless you are reimplementing the + * non blocking API's interrupt handler routines to add special functionality. + * param base The LPI2C peripheral base address. + * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + */ +void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle) +{ + uint32_t flags; + lpi2c_slave_transfer_t *xfer; + + /* Check for a valid handle in case of a spurious interrupt. */ + if (!handle) + { + return; + } + + xfer = &handle->transfer; + + /* Get status flags. */ + flags = LPI2C_SlaveGetStatusFlags(base); + + if (flags & (kLPI2C_SlaveBitErrFlag | kLPI2C_SlaveFifoErrFlag)) + { + xfer->event = kLPI2C_SlaveCompletionEvent; + xfer->completionStatus = LPI2C_SlaveCheckAndClearError(base, flags); + + if ((handle->eventMask & kLPI2C_SlaveCompletionEvent) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + return; + } + if (flags & (kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag)) + { + xfer->event = (flags & kLPI2C_SlaveRepeatedStartDetectFlag) ? kLPI2C_SlaveRepeatedStartEvent : + kLPI2C_SlaveCompletionEvent; + xfer->receivedAddress = 0; + xfer->completionStatus = kStatus_Success; + xfer->transferredCount = handle->transferredCount; + + if (xfer->event == kLPI2C_SlaveCompletionEvent) + { + handle->isBusy = false; + } + + if (handle->wasTransmit) + { + /* Subtract one from the transmit count to offset the fact that LPI2C asserts the */ + /* tx flag before it sees the nack from the master-receiver, thus causing one more */ + /* count that the master actually receives. */ + --xfer->transferredCount; + handle->wasTransmit = false; + } + + /* Clear the flag. */ + LPI2C_SlaveClearStatusFlags(base, flags & (kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag)); + + /* Revert to sending an Ack by default, in case we sent a Nack for receive. */ + base->STAR = 0; + + if ((handle->eventMask & xfer->event) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clean up transfer info on completion, after the callback has been invoked. */ + memset(&handle->transfer, 0, sizeof(handle->transfer)); + } + if (flags & kLPI2C_SlaveAddressValidFlag) + { + xfer->event = kLPI2C_SlaveAddressMatchEvent; + xfer->receivedAddress = base->SASR & LPI2C_SASR_RADDR_MASK; + + /* Update handle status to busy because slave is addressed. */ + handle->isBusy = true; + if ((handle->eventMask & kLPI2C_SlaveAddressMatchEvent) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + } + if (flags & kLPI2C_SlaveTransmitAckFlag) + { + xfer->event = kLPI2C_SlaveTransmitAckEvent; + + if ((handle->eventMask & kLPI2C_SlaveTransmitAckEvent) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + } + + /* Handle transmit and receive. */ + if (flags & kLPI2C_SlaveTxReadyFlag) + { + handle->wasTransmit = true; + + /* If we're out of data, invoke callback to get more. */ + if ((!xfer->data) || (!xfer->dataSize)) + { + xfer->event = kLPI2C_SlaveTransmitEvent; + if (handle->callback) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clear the transferred count now that we have a new buffer. */ + handle->transferredCount = 0; + } + + /* Transmit a byte. */ + if ((xfer->data) && (xfer->dataSize)) + { + base->STDR = *xfer->data++; + --xfer->dataSize; + ++handle->transferredCount; + } + } + if (flags & kLPI2C_SlaveRxReadyFlag) + { + /* If we're out of room in the buffer, invoke callback to get another. */ + if ((!xfer->data) || (!xfer->dataSize)) + { + xfer->event = kLPI2C_SlaveReceiveEvent; + if (handle->callback) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clear the transferred count now that we have a new buffer. */ + handle->transferredCount = 0; + } + + /* Receive a byte. */ + if ((xfer->data) && (xfer->dataSize)) + { + *xfer->data++ = base->SRDR; + --xfer->dataSize; + ++handle->transferredCount; + } + else + { + /* We don't have any room to receive more data, so send a nack. */ + base->STAR = LPI2C_STAR_TXNACK_MASK; + } + } +} + +/*! + * @brief Shared IRQ handler that can call both master and slave ISRs. + * + * The master and slave ISRs are called through function pointers in order to decouple + * this code from the ISR functions. Without this, the linker would always pull in both + * ISRs and every function they call, even if only the functional API was used. + * + * @param base The LPI2C peripheral base address. + * @param instance The LPI2C peripheral instance number. + */ +static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance) +{ + /* Check for master IRQ. */ + if ((base->MCR & LPI2C_MCR_MEN_MASK) && s_lpi2cMasterIsr) + { + /* Master mode. */ + s_lpi2cMasterIsr(base, s_lpi2cMasterHandle[instance]); + } + + /* Check for slave IRQ. */ + if ((base->SCR & LPI2C_SCR_SEN_MASK) && s_lpi2cSlaveIsr) + { + /* Slave mode. */ + s_lpi2cSlaveIsr(base, s_lpi2cSlaveHandle[instance]); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +#if defined(LPI2C0) +/* Implementation of LPI2C0 handler named in startup code. */ +void LPI2C0_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C0, 0); +} +#endif + +#if defined(LPI2C1) +/* Implementation of LPI2C1 handler named in startup code. */ +void LPI2C1_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C1, 1); +} +#endif + +#if defined(LPI2C2) +/* Implementation of LPI2C2 handler named in startup code. */ +void LPI2C2_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C2, 2); +} +#endif + +#if defined(LPI2C3) +/* Implementation of LPI2C3 handler named in startup code. */ +void LPI2C3_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C3, 3); +} +#endif + +#if defined(LPI2C4) +/* Implementation of LPI2C4 handler named in startup code. */ +void LPI2C4_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(LPI2C4, 4); +} +#endif + +#if defined(CM4_0__LPI2C) +/* Implementation of CM4_0__LPI2C handler named in startup code. */ +void M4_0_LPI2C_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(CM4_0__LPI2C, LPI2C_GetInstance(CM4_0__LPI2C)); +} +#endif + +#if defined(CM4__LPI2C) +/* Implementation of CM4__LPI2C handler named in startup code. */ +void M4_LPI2C_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(CM4__LPI2C, LPI2C_GetInstance(CM4__LPI2C)); +} +#endif + +#if defined(CM4_1__LPI2C) +/* Implementation of CM4_1__LPI2C handler named in startup code. */ +void M4_1_LPI2C_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(CM4_1__LPI2C, LPI2C_GetInstance(CM4_1__LPI2C)); +} +#endif + +#if defined(DMA__LPI2C0) +/* Implementation of DMA__LPI2C0 handler named in startup code. */ +void DMA_I2C0_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C0, LPI2C_GetInstance(DMA__LPI2C0)); +} +#endif + +#if defined(DMA__LPI2C1) +/* Implementation of DMA__LPI2C1 handler named in startup code. */ +void DMA_I2C1_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C1, LPI2C_GetInstance(DMA__LPI2C1)); +} +#endif + +#if defined(DMA__LPI2C2) +/* Implementation of DMA__LPI2C2 handler named in startup code. */ +void DMA_I2C2_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C2, LPI2C_GetInstance(DMA__LPI2C2)); +} +#endif + +#if defined(DMA__LPI2C3) +/* Implementation of DMA__LPI2C3 handler named in startup code. */ +void DMA_I2C3_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C3, LPI2C_GetInstance(DMA__LPI2C3)); +} +#endif + +#if defined(DMA__LPI2C4) +/* Implementation of DMA__LPI2C3 handler named in startup code. */ +void DMA_I2C4_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(DMA__LPI2C4, LPI2C_GetInstance(DMA__LPI2C4)); +} +#endif + +#if defined(ADMA__LPI2C0) +/* Implementation of DMA__LPI2C0 handler named in startup code. */ +void ADMA_I2C0_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C0, LPI2C_GetInstance(ADMA__LPI2C0)); +} +#endif + +#if defined(ADMA__LPI2C1) +/* Implementation of DMA__LPI2C1 handler named in startup code. */ +void ADMA_I2C1_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C1, LPI2C_GetInstance(ADMA__LPI2C1)); +} +#endif + +#if defined(ADMA__LPI2C2) +/* Implementation of DMA__LPI2C2 handler named in startup code. */ +void ADMA_I2C2_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C2, LPI2C_GetInstance(ADMA__LPI2C2)); +} +#endif + +#if defined(ADMA__LPI2C3) +/* Implementation of DMA__LPI2C3 handler named in startup code. */ +void ADMA_I2C3_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C3, LPI2C_GetInstance(ADMA__LPI2C3)); +} +#endif + +#if defined(ADMA__LPI2C4) +/* Implementation of DMA__LPI2C3 handler named in startup code. */ +void ADMA_I2C4_INT_DriverIRQHandler(void) +{ + LPI2C_CommonIRQHandler(ADMA__LPI2C4, LPI2C_GetInstance(ADMA__LPI2C4)); +} +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/fsl_lpi2c.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/fsl_lpi2c.h new file mode 100755 index 000000000..086fcf7e2 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/fsl_lpi2c.h @@ -0,0 +1,1266 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_LPI2C_H_ +#define _FSL_LPI2C_H_ + +#include +#include "fsl_device_registers.h" +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @addtogroup lpi2c + * @{ + */ + +/*! @name Driver version */ +/*@{*/ +/*! @brief LPI2C driver version 2.1.9. */ +#define FSL_LPI2C_DRIVER_VERSION (MAKE_VERSION(2, 1, 9)) +/*@}*/ + +/*! @brief Timeout times for waiting flag. */ +#ifndef LPI2C_WAIT_TIMEOUT +#define LPI2C_WAIT_TIMEOUT 0U /* Define to zero means keep waiting until the flag is assert/deassert. */ +#endif + +/*! @brief LPI2C status return codes. */ +enum _lpi2c_status +{ + kStatus_LPI2C_Busy = MAKE_STATUS(kStatusGroup_LPI2C, 0), /*!< The master is already performing a transfer. */ + kStatus_LPI2C_Idle = MAKE_STATUS(kStatusGroup_LPI2C, 1), /*!< The slave driver is idle. */ + kStatus_LPI2C_Nak = MAKE_STATUS(kStatusGroup_LPI2C, 2), /*!< The slave device sent a NAK in response to a byte. */ + kStatus_LPI2C_FifoError = MAKE_STATUS(kStatusGroup_LPI2C, 3), /*!< FIFO under run or overrun. */ + kStatus_LPI2C_BitError = MAKE_STATUS(kStatusGroup_LPI2C, 4), /*!< Transferred bit was not seen on the bus. */ + kStatus_LPI2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_LPI2C, 5), /*!< Arbitration lost error. */ + kStatus_LPI2C_PinLowTimeout = + MAKE_STATUS(kStatusGroup_LPI2C, 6), /*!< SCL or SDA were held low longer than the timeout. */ + kStatus_LPI2C_NoTransferInProgress = + MAKE_STATUS(kStatusGroup_LPI2C, 7), /*!< Attempt to abort a transfer when one is not in progress. */ + kStatus_LPI2C_DmaRequestFail = MAKE_STATUS(kStatusGroup_LPI2C, 8), /*!< DMA request failed. */ + kStatus_LPI2C_Timeout = MAKE_STATUS(kStatusGroup_LPI2C, 9), /*!< Timeout poling status flags. */ +}; + +/*! @} */ + +/*! + * @addtogroup lpi2c_master_driver + * @{ + */ + +/*! + * @brief LPI2C master peripheral flags. + * + * The following status register flags can be cleared: + * - #kLPI2C_MasterEndOfPacketFlag + * - #kLPI2C_MasterStopDetectFlag + * - #kLPI2C_MasterNackDetectFlag + * - #kLPI2C_MasterArbitrationLostFlag + * - #kLPI2C_MasterFifoErrFlag + * - #kLPI2C_MasterPinLowTimeoutFlag + * - #kLPI2C_MasterDataMatchFlag + * + * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as + * interrupts. + * + * @note These enums are meant to be OR'd together to form a bit mask. + */ +enum _lpi2c_master_flags +{ + kLPI2C_MasterTxReadyFlag = LPI2C_MSR_TDF_MASK, /*!< Transmit data flag */ + kLPI2C_MasterRxReadyFlag = LPI2C_MSR_RDF_MASK, /*!< Receive data flag */ + kLPI2C_MasterEndOfPacketFlag = LPI2C_MSR_EPF_MASK, /*!< End Packet flag */ + kLPI2C_MasterStopDetectFlag = LPI2C_MSR_SDF_MASK, /*!< Stop detect flag */ + kLPI2C_MasterNackDetectFlag = LPI2C_MSR_NDF_MASK, /*!< NACK detect flag */ + kLPI2C_MasterArbitrationLostFlag = LPI2C_MSR_ALF_MASK, /*!< Arbitration lost flag */ + kLPI2C_MasterFifoErrFlag = LPI2C_MSR_FEF_MASK, /*!< FIFO error flag */ + kLPI2C_MasterPinLowTimeoutFlag = LPI2C_MSR_PLTF_MASK, /*!< Pin low timeout flag */ + kLPI2C_MasterDataMatchFlag = LPI2C_MSR_DMF_MASK, /*!< Data match flag */ + kLPI2C_MasterBusyFlag = LPI2C_MSR_MBF_MASK, /*!< Master busy flag */ + kLPI2C_MasterBusBusyFlag = LPI2C_MSR_BBF_MASK /*!< Bus busy flag */ +}; + +/*! @brief Direction of master and slave transfers. */ +typedef enum _lpi2c_direction +{ + kLPI2C_Write = 0U, /*!< Master transmit. */ + kLPI2C_Read = 1U /*!< Master receive. */ +} lpi2c_direction_t; + +/*! @brief LPI2C pin configuration. */ +typedef enum _lpi2c_master_pin_config +{ + kLPI2C_2PinOpenDrain = 0x0U, /*!< LPI2C Configured for 2-pin open drain mode */ + kLPI2C_2PinOutputOnly = 0x1U, /*!< LPI2C Configured for 2-pin output only mode (ultra-fast mode) */ + kLPI2C_2PinPushPull = 0x2U, /*!< LPI2C Configured for 2-pin push-pull mode */ + kLPI2C_4PinPushPull = 0x3U, /*!< LPI2C Configured for 4-pin push-pull mode */ + kLPI2C_2PinOpenDrainWithSeparateSlave = + 0x4U, /*!< LPI2C Configured for 2-pin open drain mode with separate LPI2C slave */ + kLPI2C_2PinOutputOnlyWithSeparateSlave = + 0x5U, /*!< LPI2C Configured for 2-pin output only mode(ultra-fast mode) with separate LPI2C slave */ + kLPI2C_2PinPushPullWithSeparateSlave = + 0x6U, /*!< LPI2C Configured for 2-pin push-pull mode with separate LPI2C slave */ + kLPI2C_4PinPushPullWithInvertedOutput = 0x7U /*!< LPI2C Configured for 4-pin push-pull mode(inverted outputs) */ +} lpi2c_master_pin_config_t; + +/*! @brief LPI2C master host request selection. */ +typedef enum _lpi2c_host_request_source +{ + kLPI2C_HostRequestExternalPin = 0x0U, /*!< Select the LPI2C_HREQ pin as the host request input */ + kLPI2C_HostRequestInputTrigger = 0x1U, /*!< Select the input trigger as the host request input */ +} lpi2c_host_request_source_t; + +/*! @brief LPI2C master host request pin polarity configuration. */ +typedef enum _lpi2c_host_request_polarity +{ + kLPI2C_HostRequestPinActiveLow = 0x0U, /*!< Configure the LPI2C_HREQ pin active low */ + kLPI2C_HostRequestPinActiveHigh = 0x1U /*!< Configure the LPI2C_HREQ pin active high */ +} lpi2c_host_request_polarity_t; + +/*! + * @brief Structure with settings to initialize the LPI2C master module. + * + * This structure holds configuration settings for the LPI2C peripheral. To initialize this + * structure to reasonable defaults, call the LPI2C_MasterGetDefaultConfig() function and + * pass a pointer to your configuration structure instance. + * + * The configuration structure can be made constant so it resides in flash. + */ +typedef struct _lpi2c_master_config +{ + bool enableMaster; /*!< Whether to enable master mode. */ + bool enableDoze; /*!< Whether master is enabled in doze mode. */ + bool debugEnable; /*!< Enable transfers to continue when halted in debug mode. */ + bool ignoreAck; /*!< Whether to ignore ACK/NACK. */ + lpi2c_master_pin_config_t pinConfig; /*!< The pin configuration option. */ + uint32_t baudRate_Hz; /*!< Desired baud rate in Hertz. */ + uint32_t busIdleTimeout_ns; /*!< Bus idle timeout in nanoseconds. Set to 0 to disable. */ + uint32_t pinLowTimeout_ns; /*!< Pin low timeout in nanoseconds. Set to 0 to disable. */ + uint8_t sdaGlitchFilterWidth_ns; /*!< Width in nanoseconds of glitch filter on SDA pin. Set to 0 to disable. */ + uint8_t sclGlitchFilterWidth_ns; /*!< Width in nanoseconds of glitch filter on SCL pin. Set to 0 to disable. */ + struct + { + bool enable; /*!< Enable host request. */ + lpi2c_host_request_source_t source; /*!< Host request source. */ + lpi2c_host_request_polarity_t polarity; /*!< Host request pin polarity. */ + } hostRequest; /*!< Host request options. */ +} lpi2c_master_config_t; + +/*! @brief LPI2C master data match configuration modes. */ +typedef enum _lpi2c_data_match_config_mode +{ + kLPI2C_MatchDisabled = 0x0U, /*!< LPI2C Match Disabled */ + kLPI2C_1stWordEqualsM0OrM1 = 0x2U, /*!< LPI2C Match Enabled and 1st data word equals MATCH0 OR MATCH1 */ + kLPI2C_AnyWordEqualsM0OrM1 = 0x3U, /*!< LPI2C Match Enabled and any data word equals MATCH0 OR MATCH1 */ + kLPI2C_1stWordEqualsM0And2ndWordEqualsM1 = + 0x4U, /*!< LPI2C Match Enabled and 1st data word equals MATCH0, 2nd data equals MATCH1 */ + kLPI2C_AnyWordEqualsM0AndNextWordEqualsM1 = + 0x5U, /*!< LPI2C Match Enabled and any data word equals MATCH0, next data equals MATCH1 */ + kLPI2C_1stWordAndM1EqualsM0AndM1 = + 0x6U, /*!< LPI2C Match Enabled and 1st data word and MATCH0 equals MATCH0 and MATCH1 */ + kLPI2C_AnyWordAndM1EqualsM0AndM1 = + 0x7U /*!< LPI2C Match Enabled and any data word and MATCH0 equals MATCH0 and MATCH1 */ +} lpi2c_data_match_config_mode_t; + +/*! @brief LPI2C master data match configuration structure. */ +typedef struct _lpi2c_match_config +{ + lpi2c_data_match_config_mode_t matchMode; /*!< Data match configuration setting. */ + bool rxDataMatchOnly; /*!< When set to true, received data is ignored until a successful match. */ + uint32_t match0; /*!< Match value 0. */ + uint32_t match1; /*!< Match value 1. */ +} lpi2c_data_match_config_t; + +/* Forward declaration of the transfer descriptor and handle typedefs. */ +typedef struct _lpi2c_master_transfer lpi2c_master_transfer_t; +typedef struct _lpi2c_master_handle lpi2c_master_handle_t; + +/*! + * @brief Master completion callback function pointer type. + * + * This callback is used only for the non-blocking master transfer API. Specify the callback you wish to use + * in the call to LPI2C_MasterTransferCreateHandle(). + * + * @param base The LPI2C peripheral base address. + * @param completionStatus Either #kStatus_Success or an error code describing how the transfer completed. + * @param userData Arbitrary pointer-sized value passed from the application. + */ +typedef void (*lpi2c_master_transfer_callback_t)(LPI2C_Type *base, + lpi2c_master_handle_t *handle, + status_t completionStatus, + void *userData); + +/*! + * @brief Transfer option flags. + * + * @note These enumerations are intended to be OR'd together to form a bit mask of options for + * the #_lpi2c_master_transfer::flags field. + */ +enum _lpi2c_master_transfer_flags +{ + kLPI2C_TransferDefaultFlag = 0x00U, /*!< Transfer starts with a start signal, stops with a stop signal. */ + kLPI2C_TransferNoStartFlag = 0x01U, /*!< Don't send a start condition, address, and sub address */ + kLPI2C_TransferRepeatedStartFlag = 0x02U, /*!< Send a repeated start condition */ + kLPI2C_TransferNoStopFlag = 0x04U, /*!< Don't send a stop condition. */ +}; + +/*! + * @brief Non-blocking transfer descriptor structure. + * + * This structure is used to pass transaction parameters to the LPI2C_MasterTransferNonBlocking() API. + */ +struct _lpi2c_master_transfer +{ + uint32_t flags; /*!< Bit mask of options for the transfer. See enumeration #_lpi2c_master_transfer_flags for + available options. Set to 0 or #kLPI2C_TransferDefaultFlag for normal transfers. */ + uint16_t slaveAddress; /*!< The 7-bit slave address. */ + lpi2c_direction_t direction; /*!< Either #kLPI2C_Read or #kLPI2C_Write. */ + uint32_t subaddress; /*!< Sub address. Transferred MSB first. */ + size_t subaddressSize; /*!< Length of sub address to send in bytes. Maximum size is 4 bytes. */ + void *data; /*!< Pointer to data to transfer. */ + size_t dataSize; /*!< Number of bytes to transfer. */ +}; + +/*! + * @brief Driver handle for master non-blocking APIs. + * @note The contents of this structure are private and subject to change. + */ +struct _lpi2c_master_handle +{ + uint8_t state; /*!< Transfer state machine current state. */ + uint16_t remainingBytes; /*!< Remaining byte count in current state. */ + uint8_t *buf; /*!< Buffer pointer for current state. */ + uint16_t commandBuffer[7]; /*!< LPI2C command sequence. */ + lpi2c_master_transfer_t transfer; /*!< Copy of the current transfer info. */ + lpi2c_master_transfer_callback_t completionCallback; /*!< Callback function pointer. */ + void *userData; /*!< Application data passed to callback. */ +}; + +/*! @} */ + +/*! + * @addtogroup lpi2c_slave_driver + * @{ + */ + +/*! + * @brief LPI2C slave peripheral flags. + * + * The following status register flags can be cleared: + * - #kLPI2C_SlaveRepeatedStartDetectFlag + * - #kLPI2C_SlaveStopDetectFlag + * - #kLPI2C_SlaveBitErrFlag + * - #kLPI2C_SlaveFifoErrFlag + * + * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as + * interrupts. + * + * @note These enumerations are meant to be OR'd together to form a bit mask. + */ +enum _lpi2c_slave_flags +{ + kLPI2C_SlaveTxReadyFlag = LPI2C_SSR_TDF_MASK, /*!< Transmit data flag */ + kLPI2C_SlaveRxReadyFlag = LPI2C_SSR_RDF_MASK, /*!< Receive data flag */ + kLPI2C_SlaveAddressValidFlag = LPI2C_SSR_AVF_MASK, /*!< Address valid flag */ + kLPI2C_SlaveTransmitAckFlag = LPI2C_SSR_TAF_MASK, /*!< Transmit ACK flag */ + kLPI2C_SlaveRepeatedStartDetectFlag = LPI2C_SSR_RSF_MASK, /*!< Repeated start detect flag */ + kLPI2C_SlaveStopDetectFlag = LPI2C_SSR_SDF_MASK, /*!< Stop detect flag */ + kLPI2C_SlaveBitErrFlag = LPI2C_SSR_BEF_MASK, /*!< Bit error flag */ + kLPI2C_SlaveFifoErrFlag = LPI2C_SSR_FEF_MASK, /*!< FIFO error flag */ + kLPI2C_SlaveAddressMatch0Flag = LPI2C_SSR_AM0F_MASK, /*!< Address match 0 flag */ + kLPI2C_SlaveAddressMatch1Flag = LPI2C_SSR_AM1F_MASK, /*!< Address match 1 flag */ + kLPI2C_SlaveGeneralCallFlag = LPI2C_SSR_GCF_MASK, /*!< General call flag */ + kLPI2C_SlaveBusyFlag = LPI2C_SSR_SBF_MASK, /*!< Master busy flag */ + kLPI2C_SlaveBusBusyFlag = LPI2C_SSR_BBF_MASK, /*!< Bus busy flag */ +}; + +/*! @brief LPI2C slave address match options. */ +typedef enum _lpi2c_slave_address_match +{ + kLPI2C_MatchAddress0 = 0U, /*!< Match only address 0. */ + kLPI2C_MatchAddress0OrAddress1 = 2U, /*!< Match either address 0 or address 1. */ + kLPI2C_MatchAddress0ThroughAddress1 = 6U, /*!< Match a range of slave addresses from address 0 through address 1. */ +} lpi2c_slave_address_match_t; + +/*! + * @brief Structure with settings to initialize the LPI2C slave module. + * + * This structure holds configuration settings for the LPI2C slave peripheral. To initialize this + * structure to reasonable defaults, call the LPI2C_SlaveGetDefaultConfig() function and + * pass a pointer to your configuration structure instance. + * + * The configuration structure can be made constant so it resides in flash. + */ +typedef struct _lpi2c_slave_config +{ + bool enableSlave; /*!< Enable slave mode. */ + uint8_t address0; /*!< Slave's 7-bit address. */ + uint8_t address1; /*!< Alternate slave 7-bit address. */ + lpi2c_slave_address_match_t addressMatchMode; /*!< Address matching options. */ + bool filterDozeEnable; /*!< Enable digital glitch filter in doze mode. */ + bool filterEnable; /*!< Enable digital glitch filter. */ + bool enableGeneralCall; /*!< Enable general call address matching. */ + struct + { + bool enableAck; /*!< Enables SCL clock stretching during slave-transmit address byte(s) + and slave-receiver address and data byte(s) to allow software to + write the Transmit ACK Register before the ACK or NACK is transmitted. + Clock stretching occurs when transmitting the 9th bit. When + enableAckSCLStall is enabled, there is no need to set either + enableRxDataSCLStall or enableAddressSCLStall. */ + bool enableTx; /*!< Enables SCL clock stretching when the transmit data flag is set + during a slave-transmit transfer. */ + bool enableRx; /*!< Enables SCL clock stretching when receive data flag is set during + a slave-receive transfer. */ + bool enableAddress; /*!< Enables SCL clock stretching when the address valid flag is asserted. */ + } sclStall; + bool ignoreAck; /*!< Continue transfers after a NACK is detected. */ + bool enableReceivedAddressRead; /*!< Enable reading the address received address as the first byte of data. */ + uint32_t sdaGlitchFilterWidth_ns; /*!< Width in nanoseconds of the digital filter on the SDA signal. */ + uint32_t sclGlitchFilterWidth_ns; /*!< Width in nanoseconds of the digital filter on the SCL signal. */ + uint32_t dataValidDelay_ns; /*!< Width in nanoseconds of the data valid delay. */ + uint32_t clockHoldTime_ns; /*!< Width in nanoseconds of the clock hold time. */ +} lpi2c_slave_config_t; + +/*! + * @brief Set of events sent to the callback for non blocking slave transfers. + * + * These event enumerations are used for two related purposes. First, a bit mask created by OR'ing together + * events is passed to LPI2C_SlaveTransferNonBlocking() in order to specify which events to enable. + * Then, when the slave callback is invoked, it is passed the current event through its @a transfer + * parameter. + * + * @note These enumerations are meant to be OR'd together to form a bit mask of events. + */ +typedef enum _lpi2c_slave_transfer_event +{ + kLPI2C_SlaveAddressMatchEvent = 0x01U, /*!< Received the slave address after a start or repeated start. */ + kLPI2C_SlaveTransmitEvent = 0x02U, /*!< Callback is requested to provide data to transmit + (slave-transmitter role). */ + kLPI2C_SlaveReceiveEvent = 0x04U, /*!< Callback is requested to provide a buffer in which to place received + data (slave-receiver role). */ + kLPI2C_SlaveTransmitAckEvent = 0x08U, /*!< Callback needs to either transmit an ACK or NACK. */ + kLPI2C_SlaveRepeatedStartEvent = 0x10U, /*!< A repeated start was detected. */ + kLPI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected, completing the transfer. */ + + /*! Bit mask of all available events. */ + kLPI2C_SlaveAllEvents = kLPI2C_SlaveAddressMatchEvent | kLPI2C_SlaveTransmitEvent | kLPI2C_SlaveReceiveEvent | + kLPI2C_SlaveTransmitAckEvent | kLPI2C_SlaveRepeatedStartEvent | kLPI2C_SlaveCompletionEvent, +} lpi2c_slave_transfer_event_t; + +/*! @brief LPI2C slave transfer structure */ +typedef struct _lpi2c_slave_transfer +{ + lpi2c_slave_transfer_event_t event; /*!< Reason the callback is being invoked. */ + uint8_t receivedAddress; /*!< Matching address send by master. */ + uint8_t *data; /*!< Transfer buffer */ + size_t dataSize; /*!< Transfer size */ + status_t completionStatus; /*!< Success or error code describing how the transfer completed. Only applies for + #kLPI2C_SlaveCompletionEvent. */ + size_t transferredCount; /*!< Number of bytes actually transferred since start or last repeated start. */ +} lpi2c_slave_transfer_t; + +/* Forward declaration. */ +typedef struct _lpi2c_slave_handle lpi2c_slave_handle_t; + +/*! + * @brief Slave event callback function pointer type. + * + * This callback is used only for the slave non-blocking transfer API. To install a callback, + * use the LPI2C_SlaveSetCallback() function after you have created a handle. + * + * @param base Base address for the LPI2C instance on which the event occurred. + * @param transfer Pointer to transfer descriptor containing values passed to and/or from the callback. + * @param userData Arbitrary pointer-sized value passed from the application. + */ +typedef void (*lpi2c_slave_transfer_callback_t)(LPI2C_Type *base, lpi2c_slave_transfer_t *transfer, void *userData); + +/*! + * @brief LPI2C slave handle structure. + * @note The contents of this structure are private and subject to change. + */ +struct _lpi2c_slave_handle +{ + lpi2c_slave_transfer_t transfer; /*!< LPI2C slave transfer copy. */ + bool isBusy; /*!< Whether transfer is busy. */ + bool wasTransmit; /*!< Whether the last transfer was a transmit. */ + uint32_t eventMask; /*!< Mask of enabled events. */ + uint32_t transferredCount; /*!< Count of bytes transferred. */ + lpi2c_slave_transfer_callback_t callback; /*!< Callback function called at transfer event. */ + void *userData; /*!< Callback parameter passed to callback. */ +}; + +/*! @} */ + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @addtogroup lpi2c_master_driver + * @{ + */ + +/*! @name Initialization and deinitialization */ +/*@{*/ + +/*! + * @brief Provides a default configuration for the LPI2C master peripheral. + * + * This function provides the following default configuration for the LPI2C master peripheral: + * @code + * masterConfig->enableMaster = true; + * masterConfig->debugEnable = false; + * masterConfig->ignoreAck = false; + * masterConfig->pinConfig = kLPI2C_2PinOpenDrain; + * masterConfig->baudRate_Hz = 100000U; + * masterConfig->busIdleTimeout_ns = 0; + * masterConfig->pinLowTimeout_ns = 0; + * masterConfig->sdaGlitchFilterWidth_ns = 0; + * masterConfig->sclGlitchFilterWidth_ns = 0; + * masterConfig->hostRequest.enable = false; + * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin; + * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh; + * @endcode + * + * After calling this function, you can override any settings in order to customize the configuration, + * prior to initializing the master driver with LPI2C_MasterInit(). + * + * @param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t. + */ +void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig); + +/*! + * @brief Initializes the LPI2C master peripheral. + * + * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user + * provided configuration. A software reset is performed prior to configuration. + * + * @param base The LPI2C peripheral base address. + * @param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of + * defaults + * that you can override. + * @param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors, + * filter widths, and timeout periods. + */ +void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz); + +/*! + * @brief Deinitializes the LPI2C master peripheral. + * + * This function disables the LPI2C master peripheral and gates the clock. It also performs a software + * reset to restore the peripheral to reset conditions. + * + * @param base The LPI2C peripheral base address. + */ +void LPI2C_MasterDeinit(LPI2C_Type *base); + +/*! + * @brief Configures LPI2C master data match feature. + * + * @param base The LPI2C peripheral base address. + * @param config Settings for the data match feature. + */ +void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *config); + +/* Not static so it can be used from fsl_lpi2c_edma.c. */ +status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status); + +/* Not static so it can be used from fsl_lpi2c_edma.c. */ +status_t LPI2C_CheckForBusyBus(LPI2C_Type *base); + +/*! + * @brief Performs a software reset. + * + * Restores the LPI2C master peripheral to reset conditions. + * + * @param base The LPI2C peripheral base address. + */ +static inline void LPI2C_MasterReset(LPI2C_Type *base) +{ + base->MCR = LPI2C_MCR_RST_MASK; + base->MCR = 0; +} + +/*! + * @brief Enables or disables the LPI2C module as master. + * + * @param base The LPI2C peripheral base address. + * @param enable Pass true to enable or false to disable the specified LPI2C as master. + */ +static inline void LPI2C_MasterEnable(LPI2C_Type *base, bool enable) +{ + base->MCR = (base->MCR & ~LPI2C_MCR_MEN_MASK) | LPI2C_MCR_MEN(enable); +} + +/*@}*/ + +/*! @name Status */ +/*@{*/ + +/*! + * @brief Gets the LPI2C master status flags. + * + * A bit mask with the state of all LPI2C master status flags is returned. For each flag, the corresponding bit + * in the return value is set if the flag is asserted. + * + * @param base The LPI2C peripheral base address. + * @return State of the status flags: + * - 1: related status flag is set. + * - 0: related status flag is not set. + * @see _lpi2c_master_flags + */ +static inline uint32_t LPI2C_MasterGetStatusFlags(LPI2C_Type *base) +{ + return base->MSR; +} + +/*! + * @brief Clears the LPI2C master status flag state. + * + * The following status register flags can be cleared: + * - #kLPI2C_MasterEndOfPacketFlag + * - #kLPI2C_MasterStopDetectFlag + * - #kLPI2C_MasterNackDetectFlag + * - #kLPI2C_MasterArbitrationLostFlag + * - #kLPI2C_MasterFifoErrFlag + * - #kLPI2C_MasterPinLowTimeoutFlag + * - #kLPI2C_MasterDataMatchFlag + * + * Attempts to clear other flags has no effect. + * + * @param base The LPI2C peripheral base address. + * @param statusMask A bitmask of status flags that are to be cleared. The mask is composed of + * #_lpi2c_master_flags enumerators OR'd together. You may pass the result of a previous call to + * LPI2C_MasterGetStatusFlags(). + * @see _lpi2c_master_flags. + */ +static inline void LPI2C_MasterClearStatusFlags(LPI2C_Type *base, uint32_t statusMask) +{ + base->MSR = statusMask; +} + +/*@}*/ + +/*! @name Interrupts */ +/*@{*/ + +/*! + * @brief Enables the LPI2C master interrupt requests. + * + * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as + * interrupts. + * + * @param base The LPI2C peripheral base address. + * @param interruptMask Bit mask of interrupts to enable. See #_lpi2c_master_flags for the set + * of constants that should be OR'd together to form the bit mask. + */ +static inline void LPI2C_MasterEnableInterrupts(LPI2C_Type *base, uint32_t interruptMask) +{ + base->MIER |= interruptMask; +} + +/*! + * @brief Disables the LPI2C master interrupt requests. + * + * All flags except #kLPI2C_MasterBusyFlag and #kLPI2C_MasterBusBusyFlag can be enabled as + * interrupts. + * + * @param base The LPI2C peripheral base address. + * @param interruptMask Bit mask of interrupts to disable. See #_lpi2c_master_flags for the set + * of constants that should be OR'd together to form the bit mask. + */ +static inline void LPI2C_MasterDisableInterrupts(LPI2C_Type *base, uint32_t interruptMask) +{ + base->MIER &= ~interruptMask; +} + +/*! + * @brief Returns the set of currently enabled LPI2C master interrupt requests. + * + * @param base The LPI2C peripheral base address. + * @return A bitmask composed of #_lpi2c_master_flags enumerators OR'd together to indicate the + * set of enabled interrupts. + */ +static inline uint32_t LPI2C_MasterGetEnabledInterrupts(LPI2C_Type *base) +{ + return base->MIER; +} + +/*@}*/ + +/*! @name DMA control */ +/*@{*/ + +/*! + * @brief Enables or disables LPI2C master DMA requests. + * + * @param base The LPI2C peripheral base address. + * @param enableTx Enable flag for transmit DMA request. Pass true for enable, false for disable. + * @param enableRx Enable flag for receive DMA request. Pass true for enable, false for disable. + */ +static inline void LPI2C_MasterEnableDMA(LPI2C_Type *base, bool enableTx, bool enableRx) +{ + base->MDER = LPI2C_MDER_TDDE(enableTx) | LPI2C_MDER_RDDE(enableRx); +} + +/*! + * @brief Gets LPI2C master transmit data register address for DMA transfer. + * + * @param base The LPI2C peripheral base address. + * @return The LPI2C Master Transmit Data Register address. + */ +static inline uint32_t LPI2C_MasterGetTxFifoAddress(LPI2C_Type *base) +{ + return (uint32_t)&base->MTDR; +} + +/*! + * @brief Gets LPI2C master receive data register address for DMA transfer. + * + * @param base The LPI2C peripheral base address. + * @return The LPI2C Master Receive Data Register address. + */ +static inline uint32_t LPI2C_MasterGetRxFifoAddress(LPI2C_Type *base) +{ + return (uint32_t)&base->MRDR; +} + +/*@}*/ + +/*! @name FIFO control */ +/*@{*/ + +/*! + * @brief Sets the watermarks for LPI2C master FIFOs. + * + * @param base The LPI2C peripheral base address. + * @param txWords Transmit FIFO watermark value in words. The #kLPI2C_MasterTxReadyFlag flag is set whenever + * the number of words in the transmit FIFO is equal or less than @a txWords. Writing a value equal or + * greater than the FIFO size is truncated. + * @param rxWords Receive FIFO watermark value in words. The #kLPI2C_MasterRxReadyFlag flag is set whenever + * the number of words in the receive FIFO is greater than @a rxWords. Writing a value equal or greater + * than the FIFO size is truncated. + */ +static inline void LPI2C_MasterSetWatermarks(LPI2C_Type *base, size_t txWords, size_t rxWords) +{ + base->MFCR = LPI2C_MFCR_TXWATER(txWords) | LPI2C_MFCR_RXWATER(rxWords); +} + +/*! + * @brief Gets the current number of words in the LPI2C master FIFOs. + * + * @param base The LPI2C peripheral base address. + * @param[out] txCount Pointer through which the current number of words in the transmit FIFO is returned. + * Pass NULL if this value is not required. + * @param[out] rxCount Pointer through which the current number of words in the receive FIFO is returned. + * Pass NULL if this value is not required. + */ +static inline void LPI2C_MasterGetFifoCounts(LPI2C_Type *base, size_t *rxCount, size_t *txCount) +{ + if (txCount) + { + *txCount = (base->MFSR & LPI2C_MFSR_TXCOUNT_MASK) >> LPI2C_MFSR_TXCOUNT_SHIFT; + } + if (rxCount) + { + *rxCount = (base->MFSR & LPI2C_MFSR_RXCOUNT_MASK) >> LPI2C_MFSR_RXCOUNT_SHIFT; + } +} + +/*@}*/ + +/*! @name Bus operations */ +/*@{*/ + +/*! + * @brief Sets the I2C bus frequency for master transactions. + * + * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud + * rate. Do not call this function during a transfer, or the transfer is aborted. + * + * @note Please note that the second parameter is the clock frequency of LPI2C module, the third + * parameter means user configured bus baudrate, this implementation is different from other I2C drivers + * which use baudrate configuration as second parameter and source clock frequency as third parameter. + * + * @param base The LPI2C peripheral base address. + * @param sourceClock_Hz LPI2C functional clock frequency in Hertz. + * @param baudRate_Hz Requested bus frequency in Hertz. + */ +void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz); + +/*! + * @brief Returns whether the bus is idle. + * + * Requires the master mode to be enabled. + * + * @param base The LPI2C peripheral base address. + * @retval true Bus is busy. + * @retval false Bus is idle. + */ +static inline bool LPI2C_MasterGetBusIdleState(LPI2C_Type *base) +{ + return (base->MSR & LPI2C_MSR_BBF_MASK) >> LPI2C_MSR_BBF_SHIFT; +} + +/*! + * @brief Sends a START signal and slave address on the I2C bus. + * + * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure + * that another master is not occupying the bus. Then a START signal is transmitted, followed by the + * 7-bit address specified in the @a address parameter. Note that this function does not actually wait + * until the START and address are successfully sent on the bus before returning. + * + * @param base The LPI2C peripheral base address. + * @param address 7-bit slave device address, in bits [6:0]. + * @param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set + * the R/w bit (bit 0) in the transmitted slave address. + * @retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO. + * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + */ +status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir); + +/*! + * @brief Sends a repeated START signal and slave address on the I2C bus. + * + * This function is used to send a Repeated START signal when a transfer is already in progress. Like + * LPI2C_MasterStart(), it also sends the specified 7-bit address. + * + * @note This function exists primarily to maintain compatible APIs between LPI2C and I2C drivers, + * as well as to better document the intent of code that uses these APIs. + * + * @param base The LPI2C peripheral base address. + * @param address 7-bit slave device address, in bits [6:0]. + * @param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set + * the R/w bit (bit 0) in the transmitted slave address. + * @retval #kStatus_Success Repeated START signal and address were successfully enqueued in the transmit FIFO. + * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + */ +static inline status_t LPI2C_MasterRepeatedStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir) +{ + return LPI2C_MasterStart(base, address, dir); +} + +/*! + * @brief Performs a polling send transfer on the I2C bus. + * + * Sends up to @a txSize number of bytes to the previously addressed slave device. The slave may + * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this + * function returns #kStatus_LPI2C_Nak. + * + * @param base The LPI2C peripheral base address. + * @param txBuff The pointer to the data to be transferred. + * @param txSize The length in bytes of the data to be transferred. + * @retval #kStatus_Success Data was sent successfully. + * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * @retval #kStatus_LPI2C_FifoError FIFO under run or over run. + * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize); + +/*! + * @brief Performs a polling receive transfer on the I2C bus. + * + * @param base The LPI2C peripheral base address. + * @param rxBuff The pointer to the data to be transferred. + * @param rxSize The length in bytes of the data to be transferred. + * @retval #kStatus_Success Data was received successfully. + * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize); + +/*! + * @brief Sends a STOP signal on the I2C bus. + * + * This function does not return until the STOP signal is seen on the bus, or an error occurs. + * + * @param base The LPI2C peripheral base address. + * @retval #kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated. + * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterStop(LPI2C_Type *base); + +/*! + * @brief Performs a master polling transfer on the I2C bus. + * + * @note The API does not return until the transfer succeeds or fails due + * to error happens during transfer. + * + * @param base The LPI2C peripheral base address. + * @param transfer Pointer to the transfer structure. + * @retval #kStatus_Success Data was received successfully. + * @retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus. + * @retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte. + * @retval #kStatus_LPI2C_FifoError FIFO under run or overrun. + * @retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error. + * @retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout. + */ +status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer); + +/*@}*/ + +/*! @name Non-blocking */ +/*@{*/ + +/*! + * @brief Creates a new handle for the LPI2C master non-blocking APIs. + * + * The creation of a handle is for use with the non-blocking APIs. Once a handle + * is created, there is not a corresponding destroy handle. If the user wants to + * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called. + * + * + * @note The function also enables the NVIC IRQ for the input LPI2C. Need to notice + * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to + * enable the associated INTMUX IRQ in application. + * + * @param base The LPI2C peripheral base address. + * @param[out] handle Pointer to the LPI2C master driver handle. + * @param callback User provided pointer to the asynchronous callback function. + * @param userData User provided pointer to the application callback data. + */ +void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base, + lpi2c_master_handle_t *handle, + lpi2c_master_transfer_callback_t callback, + void *userData); + +/*! + * @brief Performs a non-blocking transaction on the I2C bus. + * + * @param base The LPI2C peripheral base address. + * @param handle Pointer to the LPI2C master driver handle. + * @param transfer The pointer to the transfer descriptor. + * @retval #kStatus_Success The transaction was started successfully. + * @retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking + * transaction is already in progress. + */ +status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base, + lpi2c_master_handle_t *handle, + lpi2c_master_transfer_t *transfer); + +/*! + * @brief Returns number of bytes transferred so far. + * @param base The LPI2C peripheral base address. + * @param handle Pointer to the LPI2C master driver handle. + * @param[out] count Number of bytes transferred so far by the non-blocking transaction. + * @retval #kStatus_Success + * @retval #kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. + */ +status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count); + +/*! + * @brief Terminates a non-blocking LPI2C master transmission early. + * + * @note It is not safe to call this function from an IRQ handler that has a higher priority than the + * LPI2C peripheral's IRQ priority. + * + * @param base The LPI2C peripheral base address. + * @param handle Pointer to the LPI2C master driver handle. + * @retval #kStatus_Success A transaction was successfully aborted. + * @retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress. + */ +void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle); + +/*@}*/ + +/*! @name IRQ handler */ +/*@{*/ + +/*! + * @brief Reusable routine to handle master interrupts. + * @note This function does not need to be called unless you are reimplementing the + * nonblocking API's interrupt handler routines to add special functionality. + * @param base The LPI2C peripheral base address. + * @param handle Pointer to the LPI2C master driver handle. + */ +void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, lpi2c_master_handle_t *handle); + +/*@}*/ + +/*! @} */ + +/*! + * @addtogroup lpi2c_slave_driver + * @{ + */ + +/*! @name Slave initialization and deinitialization */ +/*@{*/ + +/*! + * @brief Provides a default configuration for the LPI2C slave peripheral. + * + * This function provides the following default configuration for the LPI2C slave peripheral: + * @code + * slaveConfig->enableSlave = true; + * slaveConfig->address0 = 0U; + * slaveConfig->address1 = 0U; + * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0; + * slaveConfig->filterDozeEnable = true; + * slaveConfig->filterEnable = true; + * slaveConfig->enableGeneralCall = false; + * slaveConfig->sclStall.enableAck = false; + * slaveConfig->sclStall.enableTx = true; + * slaveConfig->sclStall.enableRx = true; + * slaveConfig->sclStall.enableAddress = true; + * slaveConfig->ignoreAck = false; + * slaveConfig->enableReceivedAddressRead = false; + * slaveConfig->sdaGlitchFilterWidth_ns = 0; + * slaveConfig->sclGlitchFilterWidth_ns = 0; + * slaveConfig->dataValidDelay_ns = 0; + * slaveConfig->clockHoldTime_ns = 0; + * @endcode + * + * After calling this function, override any settings to customize the configuration, + * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the @a + * address0 member of the configuration structure with the desired slave address. + * + * @param[out] slaveConfig User provided configuration structure that is set to default values. Refer to + * #lpi2c_slave_config_t. + */ +void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig); + +/*! + * @brief Initializes the LPI2C slave peripheral. + * + * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user + * provided configuration. + * + * @param base The LPI2C peripheral base address. + * @param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults + * that you can override. + * @param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths, + * data valid delay, and clock hold time. + */ +void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz); + +/*! + * @brief Deinitializes the LPI2C slave peripheral. + * + * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software + * reset to restore the peripheral to reset conditions. + * + * @param base The LPI2C peripheral base address. + */ +void LPI2C_SlaveDeinit(LPI2C_Type *base); + +/*! + * @brief Performs a software reset of the LPI2C slave peripheral. + * + * @param base The LPI2C peripheral base address. + */ +static inline void LPI2C_SlaveReset(LPI2C_Type *base) +{ + base->SCR = LPI2C_SCR_RST_MASK; + base->SCR = 0; +} + +/*! + * @brief Enables or disables the LPI2C module as slave. + * + * @param base The LPI2C peripheral base address. + * @param enable Pass true to enable or false to disable the specified LPI2C as slave. + */ +static inline void LPI2C_SlaveEnable(LPI2C_Type *base, bool enable) +{ + base->SCR = (base->SCR & ~LPI2C_SCR_SEN_MASK) | LPI2C_SCR_SEN(enable); +} + +/*@}*/ + +/*! @name Slave status */ +/*@{*/ + +/*! + * @brief Gets the LPI2C slave status flags. + * + * A bit mask with the state of all LPI2C slave status flags is returned. For each flag, the corresponding bit + * in the return value is set if the flag is asserted. + * + * @param base The LPI2C peripheral base address. + * @return State of the status flags: + * - 1: related status flag is set. + * - 0: related status flag is not set. + * @see _lpi2c_slave_flags + */ +static inline uint32_t LPI2C_SlaveGetStatusFlags(LPI2C_Type *base) +{ + return base->SSR; +} + +/*! + * @brief Clears the LPI2C status flag state. + * + * The following status register flags can be cleared: + * - #kLPI2C_SlaveRepeatedStartDetectFlag + * - #kLPI2C_SlaveStopDetectFlag + * - #kLPI2C_SlaveBitErrFlag + * - #kLPI2C_SlaveFifoErrFlag + * + * Attempts to clear other flags has no effect. + * + * @param base The LPI2C peripheral base address. + * @param statusMask A bitmask of status flags that are to be cleared. The mask is composed of + * #_lpi2c_slave_flags enumerators OR'd together. You may pass the result of a previous call to + * LPI2C_SlaveGetStatusFlags(). + * @see _lpi2c_slave_flags. + */ +static inline void LPI2C_SlaveClearStatusFlags(LPI2C_Type *base, uint32_t statusMask) +{ + base->SSR = statusMask; +} + +/*@}*/ + +/*! @name Slave interrupts */ +/*@{*/ + +/*! + * @brief Enables the LPI2C slave interrupt requests. + * + * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as + * interrupts. + * + * @param base The LPI2C peripheral base address. + * @param interruptMask Bit mask of interrupts to enable. See #_lpi2c_slave_flags for the set + * of constants that should be OR'd together to form the bit mask. + */ +static inline void LPI2C_SlaveEnableInterrupts(LPI2C_Type *base, uint32_t interruptMask) +{ + base->SIER |= interruptMask; +} + +/*! + * @brief Disables the LPI2C slave interrupt requests. + * + * All flags except #kLPI2C_SlaveBusyFlag and #kLPI2C_SlaveBusBusyFlag can be enabled as + * interrupts. + * + * @param base The LPI2C peripheral base address. + * @param interruptMask Bit mask of interrupts to disable. See #_lpi2c_slave_flags for the set + * of constants that should be OR'd together to form the bit mask. + */ +static inline void LPI2C_SlaveDisableInterrupts(LPI2C_Type *base, uint32_t interruptMask) +{ + base->SIER &= ~interruptMask; +} + +/*! + * @brief Returns the set of currently enabled LPI2C slave interrupt requests. + * @param base The LPI2C peripheral base address. + * @return A bitmask composed of #_lpi2c_slave_flags enumerators OR'd together to indicate the + * set of enabled interrupts. + */ +static inline uint32_t LPI2C_SlaveGetEnabledInterrupts(LPI2C_Type *base) +{ + return base->SIER; +} + +/*@}*/ + +/*! @name Slave DMA control */ +/*@{*/ + +/*! + * @brief Enables or disables the LPI2C slave peripheral DMA requests. + * + * @param base The LPI2C peripheral base address. + * @param enableAddressValid Enable flag for the address valid DMA request. Pass true for enable, false for disable. + * The address valid DMA request is shared with the receive data DMA request. + * @param enableRx Enable flag for the receive data DMA request. Pass true for enable, false for disable. + * @param enableTx Enable flag for the transmit data DMA request. Pass true for enable, false for disable. + */ +static inline void LPI2C_SlaveEnableDMA(LPI2C_Type *base, bool enableAddressValid, bool enableRx, bool enableTx) +{ + base->SDER = (base->SDER & ~(LPI2C_SDER_AVDE_MASK | LPI2C_SDER_RDDE_MASK | LPI2C_SDER_TDDE_MASK)) | + LPI2C_SDER_AVDE(enableAddressValid) | LPI2C_SDER_RDDE(enableRx) | LPI2C_SDER_TDDE(enableTx); +} + +/*@}*/ + +/*! @name Slave bus operations */ +/*@{*/ + +/*! + * @brief Returns whether the bus is idle. + * + * Requires the slave mode to be enabled. + * + * @param base The LPI2C peripheral base address. + * @retval true Bus is busy. + * @retval false Bus is idle. + */ +static inline bool LPI2C_SlaveGetBusIdleState(LPI2C_Type *base) +{ + return (base->SSR & LPI2C_SSR_BBF_MASK) >> LPI2C_SSR_BBF_SHIFT; +} + +/*! + * @brief Transmits either an ACK or NAK on the I2C bus in response to a byte from the master. + * + * Use this function to send an ACK or NAK when the #kLPI2C_SlaveTransmitAckFlag is asserted. This + * only happens if you enable the sclStall.enableAck field of the ::lpi2c_slave_config_t configuration + * structure used to initialize the slave peripheral. + * + * @param base The LPI2C peripheral base address. + * @param ackOrNack Pass true for an ACK or false for a NAK. + */ +static inline void LPI2C_SlaveTransmitAck(LPI2C_Type *base, bool ackOrNack) +{ + base->STAR = LPI2C_STAR_TXNACK(!ackOrNack); +} + +/*! + * @brief Returns the slave address sent by the I2C master. + * + * This function should only be called if the #kLPI2C_SlaveAddressValidFlag is asserted. + * + * @param base The LPI2C peripheral base address. + * @return The 8-bit address matched by the LPI2C slave. Bit 0 contains the R/w direction bit, and + * the 7-bit slave address is in the upper 7 bits. + */ +static inline uint32_t LPI2C_SlaveGetReceivedAddress(LPI2C_Type *base) +{ + return base->SASR & LPI2C_SASR_RADDR_MASK; +} + +/*! + * @brief Performs a polling send transfer on the I2C bus. + * + * @param base The LPI2C peripheral base address. + * @param txBuff The pointer to the data to be transferred. + * @param txSize The length in bytes of the data to be transferred. + * @param[out] actualTxSize + * @return Error or success status returned by API. + */ +status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize); + +/*! + * @brief Performs a polling receive transfer on the I2C bus. + * + * @param base The LPI2C peripheral base address. + * @param rxBuff The pointer to the data to be transferred. + * @param rxSize The length in bytes of the data to be transferred. + * @param[out] actualRxSize + * @return Error or success status returned by API. + */ +status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize); + +/*@}*/ + +/*! @name Slave non-blocking */ +/*@{*/ + +/*! + * @brief Creates a new handle for the LPI2C slave non-blocking APIs. + * + * The creation of a handle is for use with the non-blocking APIs. Once a handle + * is created, there is not a corresponding destroy handle. If the user wants to + * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called. + * + * @note The function also enables the NVIC IRQ for the input LPI2C. Need to notice + * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to + * enable the associated INTMUX IRQ in application. + + * @param base The LPI2C peripheral base address. + * @param[out] handle Pointer to the LPI2C slave driver handle. + * @param callback User provided pointer to the asynchronous callback function. + * @param userData User provided pointer to the application callback data. + */ +void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base, + lpi2c_slave_handle_t *handle, + lpi2c_slave_transfer_callback_t callback, + void *userData); + +/*! + * @brief Starts accepting slave transfers. + * + * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing + * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the + * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked + * from the interrupt context. + * + * The set of events received by the callback is customizable. To do so, set the @a eventMask parameter to + * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive. + * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need + * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and + * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as + * a convenient way to enable all events. + * + * @param base The LPI2C peripheral base address. + * @param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + * @param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify + * which events to send to the callback. Other accepted values are 0 to get a default set of + * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events. + * + * @retval #kStatus_Success Slave transfers were successfully started. + * @retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle. + */ +status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask); + +/*! + * @brief Gets the slave transfer status during a non-blocking transfer. + * @param base The LPI2C peripheral base address. + * @param handle Pointer to i2c_slave_handle_t structure. + * @param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not + * required. + * @retval #kStatus_Success + * @retval #kStatus_NoTransferInProgress + */ +status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count); + +/*! + * @brief Aborts the slave non-blocking transfers. + * @note This API could be called at any time to stop slave for handling the bus events. + * @param base The LPI2C peripheral base address. + * @param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + * @retval #kStatus_Success + * @retval #kStatus_LPI2C_Idle + */ +void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle); + +/*@}*/ + +/*! @name Slave IRQ handler */ +/*@{*/ + +/*! + * @brief Reusable routine to handle slave interrupts. + * @note This function does not need to be called unless you are reimplementing the + * non blocking API's interrupt handler routines to add special functionality. + * @param base The LPI2C peripheral base address. + * @param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state. + */ +void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle); + +/*@}*/ + +/*! @} */ + +#if defined(__cplusplus) +} +#endif + +#endif /* _FSL_LPI2C_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom.c new file mode 100755 index 000000000..55b3b8395 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom.c @@ -0,0 +1,110 @@ +/* + * The Clear BSD License + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted (subject to the limitations in the disclaimer below) provided + * that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsl_common.h" +#include "fsl_lpi2c.h" +#include "i2c_eeprom.h" + +/////////////////////////////EEPROM INIT///////////////////////////////////////// + +void I2C_EEPROM_Init() +{ + lpi2c_master_config_t masterConfig = {0}; + /* + * masterConfig.debugEnable = false; + * masterConfig.ignoreAck = false; + * masterConfig.pinConfig = kLPI2C_2PinOpenDrain; + * masterConfig.baudRate_Hz = 100000U; + * masterConfig.busIdleTimeout_ns = 0; + * masterConfig.pinLowTimeout_ns = 0; + * masterConfig.sdaGlitchFilterWidth_ns = 0; + * masterConfig.sclGlitchFilterWidth_ns = 0; + */ + LPI2C_MasterGetDefaultConfig(&masterConfig); + /* Change the default baudrate configuration */ + masterConfig.baudRate_Hz = I2C_EEPROM_BAUDRATE; + /* Initialize the LPI2C master peripheral */ + LPI2C_MasterInit(I2C_EEPROM_BASE, &masterConfig, I2C_EEPROM_CLOCK_FREQ); +} + +//struct _lpi2c_master_transfer +//{ +// uint32_t +// flags; /*!< Bit mask of options for the transfer. See enumeration #_lpi2c_master_transfer_flags for available +// options. Set to 0 or #kLPI2C_TransferDefaultFlag for normal transfers. */ +// uint16_t slaveAddress; /*!< The 7-bit slave address. */ +// lpi2c_direction_t direction; /*!< Either #kLPI2C_Read or #kLPI2C_Write. */ +// uint32_t subaddress; /*!< Sub address. Transferred MSB first. */ +// size_t subaddressSize; /*!< Length of sub address to send in bytes. Maximum size is 4 bytes. */ +// void *data; /*!< Pointer to data to transfer. */ +// size_t dataSize; /*!< Number of bytes to transfer. */ +//}; + +status_t I2C_EEPROM_Write(LPI2C_Type* base, uint32_t subAdd, uint8_t* dataBuff, uint16_t dataLen) +{ + // lpi2c_master_transfer_t *xfer = &(handle->xfer); + lpi2c_master_transfer_t xfer; + status_t status; + xfer.slaveAddress =(0xA0 >> 1); + xfer.direction = kLPI2C_Write; + xfer.subaddress = subAdd; + xfer.subaddressSize = 0x01; + xfer.data = dataBuff; + xfer.dataSize = dataLen; + xfer.flags = kLPI2C_TransferDefaultFlag; + status = LPI2C_MasterTransferBlocking(base, &xfer); + return status; +} + +uint32_t I2C_EEPROM_Read(LPI2C_Type* base, uint32_t subAdd, uint8_t* dataBuffer, uint16_t dataLen) +{ + lpi2c_master_transfer_t masterXfer = {0}; + status_t reVal = kStatus_Fail; + masterXfer.slaveAddress =(0XA0>>1); + masterXfer.direction = kLPI2C_Read; + masterXfer.subaddress = subAdd; + masterXfer.subaddressSize = 0x01; + masterXfer.data = dataBuffer; + masterXfer.dataSize = dataLen; + masterXfer.flags = kLPI2C_TransferDefaultFlag; + reVal = LPI2C_MasterTransferBlocking(base, &masterXfer); + + if(reVal != kStatus_Success) + { + return 1; + } + + return 0; +} + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom.h new file mode 100755 index 000000000..759b98195 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom.h @@ -0,0 +1,27 @@ +#ifndef __I2C_EEPROM_H_ +#define __I2C_EEPROM_H_ + +#include "fsl_common.h" + + +/* Macros for the touch touch controller. */ +#define I2C_EEPROM_BASE LPI2C1 + +/* Select USB1 PLL (480 MHz) as master lpi2c clock source */ +#define LPI2C_CLOCK_SOURCE_SELECT (0U) +/* Clock divider for master lpi2c clock source */ +#define LPI2C_CLOCK_SOURCE_DIVIDER (5U) + + +#define I2C_EEPROM_CLOCK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U)) +#define I2C_EEPROM_BAUDRATE 100000U + + +void I2C_EEPROM_Init ( void ); +status_t I2C_EEPROM_Write ( LPI2C_Type* base,uint32_t subAdd,uint8_t* dataBuff,uint16_t dataLen ); +uint32_t I2C_EEPROM_Read ( LPI2C_Type* base,uint32_t subAdd,uint8_t* dataBuff, uint16_t dataLen ); + +int eeprom_read(uint8_t *dat); +int eeprom_write(uint8_t *dat); + +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom_test.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom_test.c new file mode 100755 index 000000000..c3383f48c --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_eeprom_test.c @@ -0,0 +1,135 @@ +/* + * The Clear BSD License + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted (subject to the limitations in the disclaimer below) provided + * that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "board.h" +#include "fsl_debug_console.h" +#include "fsl_iomuxc.h" + +#include "fsl_gpio.h" +#include "connect_i2c.h" + +#include "fsl_lpi2c.h" +#include "i2c_eeprom.h" + +#include "pin_mux.h" +#include "clock_config.h" +#include +#include + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define i2c_print KPrintf + +#define EE_I2C_BUS_NAME I2C_BUS_NAME_1 /* I2C bus name */ +#define EE_I2C_DEV_NAME I2C_1_DEVICE_NAME_0 /* I2C device name */ +#define EE_I2C_DRV_NAME I2C_DRV_NAME_1 /* I2C driver name */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief delay a while. + */ +void I2C_EEPROM_TEST(void); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +int eeprom_read(uint8_t *dat) +{ + uint32_t ret; + ret = I2C_EEPROM_Read(I2C_EEPROM_BASE, 0, dat, 8); + return ret; +} + + +int eeprom_write(uint8_t *dat) +{ + uint32_t ret; + ret = I2C_EEPROM_Write(I2C_EEPROM_BASE, 0, dat, 8); + return ret; +} + +/*! +* @brief I2C_EEPROM_TEST: Write and Read + */ + +void I2C_EEPROM_TEST(void) +{ + uint8_t dat[8] = {0}; + + if(!I2C_EEPROM_Read(I2C_EEPROM_BASE, 0, dat, 8)) + { + i2c_print("Read from EEPROM %d %d %d %d %d %d %d %d\r\n", + dat[0], dat[1], dat[2], dat[3], dat[4], dat[5], dat[6], dat[7]); + } + + for(uint8_t i = 0; i < 8; i++) + { + dat[i] = 1; + } + + if(!I2C_EEPROM_Write(I2C_EEPROM_BASE, 0, dat, 8)) + { + i2c_print("Write to EEPROM %d %d %d %d %d %d %d %d\r\n", + dat[0], dat[1], dat[2], dat[3], dat[4], dat[5], dat[6], dat[7]); + } + + memset(dat, 0, 8); + if(!I2C_EEPROM_Read(I2C_EEPROM_BASE, 0, dat, 8)) + { + i2c_print("Read from EEPROM %d %d %d %d %d %d %d %d\r\n", + dat[0], dat[1], dat[2], dat[3], dat[4], dat[5], dat[6], dat[7]); + } +} + +int test_eerpom(void) +{ + Stm32HwI2cInit(); + BOARD_InitI2C1Pins(); + I2C_EEPROM_Init(); + I2C_EEPROM_TEST(); + return 0; +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)| SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)| SHELL_CMD_PARAM_NUM(0), + eeprom, test_eerpom, i2c eeprom); + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010.c new file mode 100755 index 000000000..d11ddb7ba --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010.c @@ -0,0 +1,127 @@ +/* + * The Clear BSD License + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted (subject to the limitations in the disclaimer below) provided + * that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file i2c_RTC_RX8010.c + * @brief I2C RTC drivers + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022.1.18 + */ + +#include "fsl_common.h" +#include "fsl_debug_console.h" +#include "fsl_lpi2c.h" +#include "i2c_rtc_rx8010.h" + + +/////////////////////////////EEPROM INIT///////////////////////////////////////// + +void I2C_Init() +{ + lpi2c_master_config_t masterConfig = {0}; + /* + * masterConfig.debugEnable = false; + * masterConfig.ignoreAck = false; + * masterConfig.pinConfig = kLPI2C_2PinOpenDrain; + * masterConfig.baudRate_Hz = 100000U; + * masterConfig.busIdleTimeout_ns = 0; + * masterConfig.pinLowTimeout_ns = 0; + * masterConfig.sdaGlitchFilterWidth_ns = 0; + * masterConfig.sclGlitchFilterWidth_ns = 0; + */ + LPI2C_MasterGetDefaultConfig(&masterConfig); + + /* Change the default baudrate configuration */ + masterConfig.baudRate_Hz = I2C_BAUDRATE; + + /* Initialize the LPI2C master peripheral */ + LPI2C_MasterInit(I2C_BASE, &masterConfig, I2C_CLOCK_FREQ); +} + +//struct _lpi2c_master_transfer +//{ +// uint32_t +// flags; /*!< Bit mask of options for the transfer. See enumeration #_lpi2c_master_transfer_flags for available +// options. Set to 0 or #kLPI2C_TransferDefaultFlag for normal transfers. */ +// uint16_t slaveAddress; /*!< The 7-bit slave address. */ +// lpi2c_direction_t direction; /*!< Either #kLPI2C_Read or #kLPI2C_Write. */ +// uint32_t subaddress; /*!< Sub address. Transferred MSB first. */ +// size_t subaddressSize; /*!< Length of sub address to send in bytes. Maximum size is 4 bytes. */ +// void *data; /*!< Pointer to data to transfer. */ +// size_t dataSize; /*!< Number of bytes to transfer. */ +//}; + +status_t I2C_Write(LPI2C_Type *base,uint32_t subAdd,uint8_t *dataBuff,uint16_t dataLen) +{ + // lpi2c_master_transfer_t *xfer = &(handle->xfer); + lpi2c_master_transfer_t xfer; + status_t status; + + xfer.slaveAddress = 0x32; ////RX8010 SLEVEADDRESS 7BIT + xfer.direction = kLPI2C_Write; + xfer.subaddress = subAdd; + xfer.subaddressSize = 0x01; + xfer.data = dataBuff; + xfer.dataSize = dataLen; + xfer.flags = kLPI2C_TransferDefaultFlag; + + status = LPI2C_MasterTransferBlocking(base, &xfer); + + return status; +} + +uint32_t I2C_Read(LPI2C_Type *base,uint32_t subAdd,uint8_t* dataBuffer, uint16_t dataLen) +{ + lpi2c_master_transfer_t masterXfer = {0}; + status_t reVal = kStatus_Fail; + + masterXfer.slaveAddress = 0x32; + masterXfer.direction = kLPI2C_Read; + masterXfer.subaddress = subAdd; + masterXfer.subaddressSize = 0x01; + masterXfer.data = dataBuffer; + masterXfer.dataSize = dataLen; + masterXfer.flags = kLPI2C_TransferDefaultFlag; + + reVal = LPI2C_MasterTransferBlocking(base, &masterXfer); + + if (reVal != kStatus_Success) + { + return 1; + } + + return 0; +} + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010.h new file mode 100755 index 000000000..95cfc52e4 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010.h @@ -0,0 +1,27 @@ +#ifndef __I2C_RTC_RX8010_H_ +#define __I2C_RTC_RX8010_H_ + +#include "fsl_common.h" + +/* Macros for the touch touch controller. */ +#define I2C_BASE LPI2C1 + +/* Select USB1 PLL (480 MHz) as master lpi2c clock source */ +#define LPI2C_CLOCK_SOURCE_SELECT (0U) +/* Clock divider for master lpi2c clock source */ +#define LPI2C_CLOCK_SOURCE_DIVIDER (5U) + +#define I2C_CLOCK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U)) +#define I2C_BAUDRATE 100000U + +#define I2C_RTC_ADDR 0x32 +#define I2C_EEPROM_ADDR 0x0 + +void I2C_Init(void); +status_t I2C_Write(LPI2C_Type *base,uint32_t subAdd,uint8_t *dataBuff,uint16_t dataLen); +uint32_t I2C_Read(LPI2C_Type *base,uint32_t subAdd,uint8_t* dataBuff, uint16_t dataLen); + +int rx8010_set_time(uint8_t* asc_date); +int rx8010_get_time(void); + +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010_test.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010_test.c new file mode 100755 index 000000000..32c04c847 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/i2c/i2c_rtc_rx8010_test.c @@ -0,0 +1,295 @@ +/* + * The Clear BSD License + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted (subject to the limitations in the disclaimer below) provided + * that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "board.h" +#include "fsl_debug_console.h" + +#include "fsl_lpi2c.h" +#include "i2c_rtc_rx8010.h" + +#include "pin_mux.h" +#include "clock_config.h" +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define EXAMPLE_DELAY_COUNT 8000000 + +#undef GETCHAR +#define GETCHAR getchar +#undef PUTCHAR +#define PUTCHAR putchar + +#define rtc_print KPrintf + +///////////RX8010/////////// + +#define RX8010_SEC 0x10 +#define RX8010_MIN 0x11 +#define RX8010_HOUR 0x12 +#define RX8010_WDAY 0x13 +#define RX8010_MDAY 0x14 +#define RX8010_MONTH 0x15 +#define RX8010_YEAR 0x16 +#define RX8010_YEAR 0x16 +#define RX8010_RESV17 0x17 +#define RX8010_ALMIN 0x18 +#define RX8010_ALHOUR 0x19 +#define RX8010_ALWDAY 0x1A +#define RX8010_TCOUNT0 0x1B +#define RX8010_TCOUNT1 0x1C +#define RX8010_EXT 0x1D +#define RX8010_FLAG 0x1E +#define RX8010_CTRL 0x1F + +/* 0x20 to 0x2F are user registers */ +#define RX8010_RESV30 0x30 +#define RX8010_RESV31 0x31 +#define RX8010_IRQ 0x32 + +#define RX8010_EXT_WADA 0x04 //BIT(3) + +#define RX8010_FLAG_VLF 0x02 //BIT(1) +#define RX8010_FLAG_AF 0x04 //BIT(3) +#define RX8010_FLAG_TF 0x08 //BIT(4) +#define RX8010_FLAG_UF 0x10 //BIT(5) + +#define RX8010_CTRL_AIE 0x04 //BIT(3) +#define RX8010_CTRL_UIE 0x10 //BIT(5) +#define RX8010_CTRL_STOP 0x20 //BIT(6) +#define RX8010_CTRL_TEST 0x40 //BIT(7) + +#define RX8010_ALARM_AE 0x40 //BIT(7) + +#define RX8010_TEST_TIME 10000 + +#define BCD_DATA_LEN 20 + +// change BIN format to BCD format +#define TO_BCD(_n) (((_n / 10) << 4) | (_n % 10)) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/******************************************************************************* + * Variables + ******************************************************************************/ +/******************************************************************************* + * Code + ******************************************************************************/ + +// change BCD format date to BIN format +uint8_t bcd2bin(uint8_t data) +{ + int i = 0; + uint8_t ret = 0; + uint8_t mask[4] = {0x01, 0x02, 0x04, 0x08}; + + //LOW + for(i = 0; i < 4; i++) + { + if(mask[i] & data) + { + ret += mask[i]; + } + } + + //HIGH + for(i = 0; i < 4; i++) + { + if(mask[i] & (data >> 4)) + { + ret += (mask[i] * 10); + } + } + + return ret; +} + +// 8010 initialization +int rx8010_init(void) +{ + uint8_t flag = 0; + uint8_t data = 0; + uint8_t ctrl[2]; + int need_clear = 0, err = 0; + + err = I2C_Read(I2C_BASE, RX8010_FLAG, &flag, 1); + flag &= ~(RX8010_FLAG_VLF); + + err = I2C_Write(I2C_BASE, RX8010_FLAG, &flag, 1); + /* Initialize reserved registers as specified in datasheet */ + + data = 0xD8; + err = I2C_Write(I2C_BASE, RX8010_RESV17, &data, 1); + + data = 0x00; + err = I2C_Write(I2C_BASE, RX8010_RESV30, &data, 1); + + data = 0x08; + err = I2C_Write(I2C_BASE, RX8010_RESV31, &data, 1); + + data = 0x00; + err = I2C_Write(I2C_BASE, RX8010_IRQ, &data, 1); + + err = I2C_Read(I2C_BASE, RX8010_FLAG, ctrl, 2); + + if(ctrl[0] & RX8010_FLAG_VLF) + { + rtc_print("\r\n Frequency stop was detected\r\n"); + } + + if(ctrl[0] & RX8010_FLAG_AF) + { + rtc_print("\r\n Alarm was detected\r\n"); + need_clear = 1; + } + + if(ctrl[0] & RX8010_FLAG_TF) + { + need_clear = 1; + } + + if(ctrl[0] & RX8010_FLAG_UF) + { + need_clear = 1; + } + + if(need_clear) + { + ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF); + err = I2C_Write(I2C_BASE, RX8010_FLAG, ctrl,1); + + if(!err) + { + return err; + } + } + + return err; +} + +// check format and get BCD format date like 2018-06-21 16:29:30 +int get_bcd_date(uint8_t* date, uint8_t* bcd_date) +{ + int i; + int temp_date[6]; + + if(sscanf(date, "20%2d-%2d-%2d %2d:%2d:%2d", + &temp_date[5], + &temp_date[4], + &temp_date[3], + &temp_date[2], + &temp_date[1], + &temp_date[0]) == EOF) + { + rtc_print("i2c %s failed\n", __func__); + return -1; + } + + for(i = 0; i < 6; i++) + { + bcd_date[i] = TO_BCD(temp_date[i]); + } + + return 0; +} + +// setup time +int rx8010_set_time(uint8_t* asc_date) +{ + uint8_t bcd_date[6]; + int ret, err; + + if(get_bcd_date(asc_date, bcd_date)) + { + rtc_print("\r\n Date format error! \r\n"); + return -1; + } + + err = I2C_Write(I2C_BASE, RX8010_SEC, bcd_date, 3); + err |= I2C_Write(I2C_BASE, RX8010_MDAY, &bcd_date[3], 3); + return err; +} + +// get rx8010 time +int rx8010_get_time(void) +{ + uint8_t date[7]; + uint8_t dateRsul[7]; + uint8_t flagreg; + int err; + err = I2C_Read(I2C_BASE, RX8010_FLAG, &flagreg, 1); + + if(flagreg & RX8010_FLAG_VLF) + { + rtc_print("\r\n Frequency stop was detected\r\n"); + return 1; + } + + err = I2C_Read(I2C_BASE, RX8010_SEC, date, 7); + dateRsul[0] = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f); + dateRsul[1] = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f); + dateRsul[2] = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f); + dateRsul[4] = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f); + dateRsul[5] = bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f); + dateRsul[6] = bcd2bin(date[RX8010_YEAR - RX8010_SEC]); + dateRsul[3] = date[RX8010_WDAY - RX8010_SEC] & 0x7f; + rtc_print("RX8010 Time: 20%d%d-%d%d-%d%d %d%d:%d%d:%d%d\r\n", + dateRsul[6]/10, dateRsul[6]%10, dateRsul[5]/10, dateRsul[5]%10, dateRsul[4]/10, dateRsul[4]%10, + dateRsul[2]/10, dateRsul[2]%10, dateRsul[1]/10, dateRsul[1]%10, dateRsul[0]/10, dateRsul[0]%10); + return 0; +} + +void test_rtc_rx8010(int argc, char *argv[]) +{ + BOARD_InitI2C1Pins(); + I2C_Init(); + rx8010_init(); + + if(argc == 2) + { + if(rx8010_set_time(argv[1]) == 0) + { + rx8010_get_time(); + } + } + else + { + rx8010_get_time(); + } +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)| SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)| SHELL_CMD_PARAM_NUM(3), + rtc, test_rtc_rx8010, i2c rtc "date time"); + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/MIMXRT1052_features.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/MIMXRT1052_features.h index 7ccb74015..f78522df6 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/MIMXRT1052_features.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/MIMXRT1052_features.h @@ -144,6 +144,8 @@ #define FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE (0) /* @brief Remove ALT Clock selection feature. */ #define FSL_FEATURE_ADC_SUPPORT_ALTCLK_REMOVE (1) +/* @brief Conversion control count (related to number of registers HCn and Rn). */ +#define FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT (8) /* ADC_ETC module features */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_ethernet.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_ethernet.h index fa18d0e83..7876dfe6e 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_ethernet.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_ethernet.h @@ -63,8 +63,6 @@ /* Exported functions ------------------------------------------------------- */ -void enet_delay(void); - #ifdef __cplusplus } #endif diff --git a/Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/include/connect_gpio.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_gpio.h similarity index 100% rename from Ubiquitous/XiUOS/board/stm32f407-st-discovery/third_party_driver/include/connect_gpio.h rename to Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_gpio.h diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_i2c.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_i2c.h new file mode 100755 index 000000000..0ffbc7dbd --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/connect_i2c.h @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_i2c.h +* @brief define stm32f407-st-discovery-board i2c function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_I2C_H +#define CONNECT_I2C_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +int Stm32HwI2cInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/enet_ethernetif.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/enet_ethernetif.h index cc7016b3b..8416d75bc 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/enet_ethernetif.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/enet_ethernetif.h @@ -38,18 +38,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file enet_ethernetif.h * @brief ethernet drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/enet_ethernetif_priv.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/enet_ethernetif_priv.h index 7fa9050b7..559466736 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/enet_ethernetif_priv.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/enet_ethernetif_priv.h @@ -5,18 +5,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file enet_ethernetif_priv.h * @brief ethernet drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_cache.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_cache.h index daf80e3df..d82e88b80 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_cache.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_cache.h @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_cache.h * @brief cache drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_clock.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_clock.h index 6324f1f09..a781e8e8f 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_clock.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_clock.h @@ -5,18 +5,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_clock.h * @brief clock drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_common.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_common.h index 0b0eca9e3..3410e8416 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_common.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_common.h @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_common.h * @brief common drivers header diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_debug_console.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_debug_console.h index c40971bfc..500bb7bf4 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_debug_console.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_debug_console.h @@ -23,7 +23,7 @@ #define _FSL_DEBUGCONSOLE_H_ #include "fsl_common.h" -//#include "serial_manager.h" +#include "serial_manager.h" /*! * @addtogroup debugconsole diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_enet.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_enet.h index 88de11960..682620d8a 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_enet.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_enet.h @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_enet.h * @brief ethernet drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_iomuxc.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_iomuxc.h index d7e9f2689..e4bb7fb26 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_iomuxc.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_iomuxc.h @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_iomuxc.h * @brief io mux drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_lpuart.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_lpuart.h index 71df1ae86..ae9d321e1 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_lpuart.h +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/fsl_lpuart.h @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_lpuart.h * @brief fsl uart drivers diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_manager.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_manager.h new file mode 100755 index 000000000..14af2c07c --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_manager.h @@ -0,0 +1,548 @@ +/* + * Copyright 2018 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SERIAL_MANAGER_H__ +#define __SERIAL_MANAGER_H__ + +/*! + * @addtogroup serialmanager + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING +/*! @brief Enable or disable serial manager non-blocking mode (1 - enable, 0 - disable) */ +#define SERIAL_MANAGER_NON_BLOCKING_MODE (1U) +#else +#ifndef SERIAL_MANAGER_NON_BLOCKING_MODE +#define SERIAL_MANAGER_NON_BLOCKING_MODE (0U) +#endif +#endif + +/*! @brief Enable or disable uart port (1 - enable, 0 - disable) */ +#ifndef SERIAL_PORT_TYPE_UART +#define SERIAL_PORT_TYPE_UART (1U) +#endif + +/*! @brief Enable or disable USB CDC port (1 - enable, 0 - disable) */ +#ifndef SERIAL_PORT_TYPE_USBCDC +#define SERIAL_PORT_TYPE_USBCDC (0U) +#endif + +/*! @brief Enable or disable SWO port (1 - enable, 0 - disable) */ +#ifndef SERIAL_PORT_TYPE_SWO +#define SERIAL_PORT_TYPE_SWO (0U) +#endif + +/*! @brief Enable or disable USB CDC virtual port (1 - enable, 0 - disable) */ +#ifndef SERIAL_PORT_TYPE_USBCDC_VIRTUAL +#define SERIAL_PORT_TYPE_USBCDC_VIRTUAL (0U) +#endif + +/*! @brief Set serial manager write handle size */ +#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U)) +#define SERIAL_MANAGER_WRITE_HANDLE_SIZE (44U) +#define SERIAL_MANAGER_READ_HANDLE_SIZE (44U) +#else +#define SERIAL_MANAGER_WRITE_HANDLE_SIZE (4U) +#define SERIAL_MANAGER_READ_HANDLE_SIZE (4U) +#endif + +#if (defined(SERIAL_PORT_TYPE_UART) && (SERIAL_PORT_TYPE_UART > 0U)) +#include "serial_port_uart.h" +#endif + +#if (defined(SERIAL_PORT_TYPE_USBCDC) && (SERIAL_PORT_TYPE_USBCDC > 0U)) + +#if !(defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U)) +#error The serial manager blocking mode cannot be supported for USB CDC. +#endif + +#include "serial_port_usb.h" +#endif + +#if (defined(SERIAL_PORT_TYPE_SWO) && (SERIAL_PORT_TYPE_SWO > 0U)) +#include "serial_port_swo.h" +#endif + +#if (defined(SERIAL_PORT_TYPE_USBCDC_VIRTUAL) && (SERIAL_PORT_TYPE_USBCDC_VIRTUAL > 0U)) + +#if !(defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U)) +#error The serial manager blocking mode cannot be supported for USB CDC. +#endif + +#include "serial_port_usb_virtual.h" +#endif + +#define SERIAL_MANAGER_HANDLE_SIZE_TEMP 0U +#if (defined(SERIAL_PORT_TYPE_UART) && (SERIAL_PORT_TYPE_UART > 0U)) + +#if (SERIAL_PORT_UART_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP) +#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP +#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_UART_HANDLE_SIZE +#endif + +#endif + +#if (defined(SERIAL_PORT_TYPE_USBCDC) && (SERIAL_PORT_TYPE_USBCDC > 0U)) + +#if (SERIAL_PORT_USB_CDC_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP) +#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP +#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_USB_CDC_HANDLE_SIZE +#endif + +#endif + +#if (defined(SERIAL_PORT_TYPE_SWO) && (SERIAL_PORT_TYPE_SWO > 0U)) + +#if (SERIAL_PORT_SWO_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP) +#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP +#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_SWO_HANDLE_SIZE +#endif + +#endif + +#if (defined(SERIAL_PORT_TYPE_USBCDC_VIRTUAL) && (SERIAL_PORT_TYPE_USBCDC_VIRTUAL > 0U)) + +#if (SERIAL_PORT_USB_VIRTUAL_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP) +#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP +#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_USB_VIRTUAL_HANDLE_SIZE +#endif + +#endif + +/*! @brief SERIAL_PORT_UART_HANDLE_SIZE/SERIAL_PORT_USB_CDC_HANDLE_SIZE + serial manager dedicated size */ +#if ((defined(SERIAL_MANAGER_HANDLE_SIZE_TEMP) && (SERIAL_MANAGER_HANDLE_SIZE_TEMP > 0U))) +#else +#error SERIAL_PORT_TYPE_UART, SERIAL_PORT_TYPE_USBCDC, SERIAL_PORT_TYPE_SWO and SERIAL_PORT_TYPE_USBCDC_VIRTUAL should not be cleared at same time. +#endif + +#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U)) +#define SERIAL_MANAGER_HANDLE_SIZE (SERIAL_MANAGER_HANDLE_SIZE_TEMP + 120U) +#else +#define SERIAL_MANAGER_HANDLE_SIZE (SERIAL_MANAGER_HANDLE_SIZE_TEMP + 12U) +#endif + +#define SERIAL_MANAGER_USE_COMMON_TASK (1U) +#define SERIAL_MANAGER_TASK_PRIORITY (2U) +#define SERIAL_MANAGER_TASK_STACK_SIZE (1000U) + +typedef void *serial_handle_t; +typedef void *serial_write_handle_t; +typedef void *serial_read_handle_t; + +/*! @brief serial port type*/ +typedef enum _serial_port_type +{ + kSerialPort_Uart = 1U, /*!< Serial port UART */ + kSerialPort_UsbCdc, /*!< Serial port USB CDC */ + kSerialPort_Swo, /*!< Serial port SWO */ + kSerialPort_UsbCdcVirtual, /*!< Serial port USB CDC Virtual */ +} serial_port_type_t; + +/*! @brief serial manager config structure*/ +typedef struct _serial_manager_config +{ + uint8_t *ringBuffer; /*!< Ring buffer address, it is used to buffer data received by the hardware. + Besides, the memory space cannot be free during the lifetime of the serial + manager module. */ + uint32_t ringBufferSize; /*!< The size of the ring buffer */ + serial_port_type_t type; /*!< Serial port type */ + void *portConfig; /*!< Serial port configuration */ +} serial_manager_config_t; + +/*! @brief serial manager error code*/ +typedef enum _serial_manager_status +{ + kStatus_SerialManager_Success = kStatus_Success, /*!< Success */ + kStatus_SerialManager_Error = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 1), /*!< Failed */ + kStatus_SerialManager_Busy = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 2), /*!< Busy */ + kStatus_SerialManager_Notify = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 3), /*!< Ring buffer is not empty */ + kStatus_SerialManager_Canceled = + MAKE_STATUS(kStatusGroup_SERIALMANAGER, 4), /*!< the non-blocking request is canceled */ + kStatus_SerialManager_HandleConflict = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 5), /*!< The handle is opened */ + kStatus_SerialManager_RingBufferOverflow = + MAKE_STATUS(kStatusGroup_SERIALMANAGER, 6), /*!< The ring buffer is overflowed */ +} serial_manager_status_t; + +/*! @brief Callback message structure */ +typedef struct _serial_manager_callback_message +{ + uint8_t *buffer; /*!< Transferred buffer */ + uint32_t length; /*!< Transferred data length */ +} serial_manager_callback_message_t; + +/*! @brief callback function */ +typedef void (*serial_manager_callback_t)(void *callbackParam, + serial_manager_callback_message_t *message, + serial_manager_status_t status); + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* _cplusplus */ + +/*! + * @brief Initializes a serial manager module with the serial manager handle and the user configuration structure. + * + * This function configures the Serial Manager module with user-defined settings. The user can configure the + * configuration + * structure. The parameter serialHandle is a pointer to point to a memory space of size #SERIAL_MANAGER_HANDLE_SIZE + * allocated by the caller. + * The Serial Manager module supports two types of serial port, UART (includes UART, USART, LPSCI, LPUART, etc) and USB + * CDC. + * Please refer to #serial_port_type_t for serial port setting. These two types can be set by using + * #serial_manager_config_t. + * + * Example below shows how to use this API to configure the Serial Manager. + * For UART, + * @code + * #define SERIAL_MANAGER_RING_BUFFER_SIZE (256U) + * static uint8_t s_serialHandleBuffer[SERIAL_MANAGER_HANDLE_SIZE]; + * static serial_handle_t s_serialHandle = &s_serialHandleBuffer[0]; + * static uint8_t s_ringBuffer[SERIAL_MANAGER_RING_BUFFER_SIZE]; + * + * serial_manager_config_t config; + * serial_port_uart_config_t uartConfig; + * config.type = kSerialPort_Uart; + * config.ringBuffer = &s_ringBuffer[0]; + * config.ringBufferSize = SERIAL_MANAGER_RING_BUFFER_SIZE; + * uartConfig.instance = 0; + * uartConfig.clockRate = 24000000; + * uartConfig.baudRate = 115200; + * uartConfig.parityMode = kSerialManager_UartParityDisabled; + * uartConfig.stopBitCount = kSerialManager_UartOneStopBit; + * uartConfig.enableRx = 1; + * uartConfig.enableTx = 1; + * config.portConfig = &uartConfig; + * SerialManager_Init(s_serialHandle, &config); + * @endcode + * For USB CDC, + * @code + * #define SERIAL_MANAGER_RING_BUFFER_SIZE (256U) + * static uint8_t s_serialHandleBuffer[SERIAL_MANAGER_HANDLE_SIZE]; + * static serial_handle_t s_serialHandle = &s_serialHandleBuffer[0]; + * static uint8_t s_ringBuffer[SERIAL_MANAGER_RING_BUFFER_SIZE]; + * + * serial_manager_config_t config; + * serial_port_usb_cdc_config_t usbCdcConfig; + * config.type = kSerialPort_UsbCdc; + * config.ringBuffer = &s_ringBuffer[0]; + * config.ringBufferSize = SERIAL_MANAGER_RING_BUFFER_SIZE; + * usbCdcConfig.controllerIndex = kSerialManager_UsbControllerKhci0; + * config.portConfig = &usbCdcConfig; + * SerialManager_Init(s_serialHandle, &config); + * @endcode + * + * @param serialHandle Pointer to point to a memory space of size #SERIAL_MANAGER_HANDLE_SIZE allocated by the caller. + * @param config Pointer to user-defined configuration structure. + * @retval kStatus_SerialManager_Error An error occurred. + * @retval kStatus_SerialManager_Success The Serial Manager module initialization succeed. + */ +serial_manager_status_t SerialManager_Init(serial_handle_t serialHandle, serial_manager_config_t *config); + +/*! + * @brief De-initializes the serial manager module instance. + * + * This function de-initializes the serial manager module instance. If the opened writing or + * reading handle is not closed, the function will return kStatus_SerialManager_Busy. + * + * @param serialHandle The serial manager module handle pointer. + * @retval kStatus_SerialManager_Success The serial manager de-initialization succeed. + * @retval kStatus_SerialManager_Busy Opened reading or writing handle is not closed. + */ +serial_manager_status_t SerialManager_Deinit(serial_handle_t serialHandle); + +/*! + * @brief Opens a writing handle for the serial manager module. + * + * This function Opens a writing handle for the serial manager module. If the serial manager needs to + * be used in different tasks, the task should open a dedicated write handle for itself by calling + * #SerialManager_OpenWriteHandle. Since there can only one buffer for transmission for the writing + * handle at the same time, multiple writing handles need to be opened when the multiple transmission + * is needed for a task. + * + * @param serialHandle The serial manager module handle pointer. + * @param writeHandle The serial manager module writing handle pointer. + * @retval kStatus_SerialManager_Error An error occurred. + * @retval kStatus_SerialManager_HandleConflict The writing handle was opened. + * @retval kStatus_SerialManager_Success The writing handle is opened. + * + * Example below shows how to use this API to write data. + * For task 1, + * @code + * static uint8_t s_serialWriteHandleBuffer1[SERIAL_MANAGER_WRITE_HANDLE_SIZE]; + * static serial_write_handle_t s_serialWriteHandle1 = &s_serialWriteHandleBuffer1[0]; + * static uint8_t s_nonBlockingWelcome1[] = "This is non-blocking writing log for task1!\r\n"; + * SerialManager_OpenWriteHandle(serialHandle, s_serialWriteHandle1); + * SerialManager_InstallTxCallback(s_serialWriteHandle1, Task1_SerialManagerTxCallback, s_serialWriteHandle1); + * SerialManager_WriteNonBlocking(s_serialWriteHandle1, s_nonBlockingWelcome1, sizeof(s_nonBlockingWelcome1) - 1); + * @endcode + * For task 2, + * @code + * static uint8_t s_serialWriteHandleBuffer2[SERIAL_MANAGER_WRITE_HANDLE_SIZE]; + * static serial_write_handle_t s_serialWriteHandle2 = &s_serialWriteHandleBuffer2[0]; + * static uint8_t s_nonBlockingWelcome2[] = "This is non-blocking writing log for task2!\r\n"; + * SerialManager_OpenWriteHandle(serialHandle, s_serialWriteHandle2); + * SerialManager_InstallTxCallback(s_serialWriteHandle2, Task2_SerialManagerTxCallback, s_serialWriteHandle2); + * SerialManager_WriteNonBlocking(s_serialWriteHandle2, s_nonBlockingWelcome2, sizeof(s_nonBlockingWelcome2) - 1); + * @endcode + */ +serial_manager_status_t SerialManager_OpenWriteHandle(serial_handle_t serialHandle, serial_write_handle_t writeHandle); + +/*! + * @brief Closes a writing handle for the serial manager module. + * + * This function Closes a writing handle for the serial manager module. + * + * @param writeHandle The serial manager module writing handle pointer. + * @retval kStatus_SerialManager_Success The writing handle is closed. + */ +serial_manager_status_t SerialManager_CloseWriteHandle(serial_write_handle_t writeHandle); + +/*! + * @brief Opens a reading handle for the serial manager module. + * + * This function Opens a reading handle for the serial manager module. The reading handle can not be + * opened multiple at the same time. The error code kStatus_SerialManager_Busy would be returned when + * the previous reading handle is not closed. And There can only be one buffer for receiving for the + * reading handle at the same time. + * + * @param serialHandle The serial manager module handle pointer. + * @param readHandle The serial manager module reading handle pointer. + * @retval kStatus_SerialManager_Error An error occurred. + * @retval kStatus_SerialManager_Success The reading handle is opened. + * @retval kStatus_SerialManager_Busy Previous reading handle is not closed. + * + * Example below shows how to use this API to read data. + * @code + * static uint8_t s_serialReadHandleBuffer[SERIAL_MANAGER_READ_HANDLE_SIZE]; + * static serial_read_handle_t s_serialReadHandle = &s_serialReadHandleBuffer[0]; + * SerialManager_OpenReadHandle(serialHandle, s_serialReadHandle); + * static uint8_t s_nonBlockingBuffer[64]; + * SerialManager_InstallRxCallback(s_serialReadHandle, APP_SerialManagerRxCallback, s_serialReadHandle); + * SerialManager_ReadNonBlocking(s_serialReadHandle, s_nonBlockingBuffer, sizeof(s_nonBlockingBuffer)); + * @endcode + */ +serial_manager_status_t SerialManager_OpenReadHandle(serial_handle_t serialHandle, serial_read_handle_t readHandle); + +/*! + * @brief Closes a reading for the serial manager module. + * + * This function Closes a reading for the serial manager module. + * + * @param readHandle The serial manager module reading handle pointer. + * @retval kStatus_SerialManager_Success The reading handle is closed. + */ +serial_manager_status_t SerialManager_CloseReadHandle(serial_read_handle_t readHandle); + +/*! + * @brief Transmits data with the blocking mode. + * + * This is a blocking function, which polls the sending queue, waits for the sending queue to be empty. + * This function sends data using an interrupt method. The interrupt of the hardware could not be disabled. + * And There can only one buffer for transmission for the writing handle at the same time. + * + * @note The function #SerialManager_WriteBlocking and the function #SerialManager_WriteNonBlocking + * cannot be used at the same time. + * And, the function #SerialManager_CancelWriting cannot be used to abort the transmission of this function. + * + * @param writeHandle The serial manager module handle pointer. + * @param buffer Start address of the data to write. + * @param length Length of the data to write. + * @retval kStatus_SerialManager_Success Successfully sent all data. + * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all sent yet. + * @retval kStatus_SerialManager_Error An error occurred. + */ +serial_manager_status_t SerialManager_WriteBlocking(serial_write_handle_t writeHandle, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Reads data with the blocking mode. + * + * This is a blocking function, which polls the receiving buffer, waits for the receiving buffer to be full. + * This function receives data using an interrupt method. The interrupt of the hardware could not be disabled. + * And There can only one buffer for receiving for the reading handle at the same time. + * + * @note The function #SerialManager_ReadBlocking and the function #SerialManager_ReadNonBlocking + * cannot be used at the same time. + * And, the function #SerialManager_CancelReading cannot be used to abort the transmission of this function. + * + * @param readHandle The serial manager module handle pointer. + * @param buffer Start address of the data to store the received data. + * @param length The length of the data to be received. + * @retval kStatus_SerialManager_Success Successfully received all data. + * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all received yet. + * @retval kStatus_SerialManager_Error An error occurred. + */ +serial_manager_status_t SerialManager_ReadBlocking(serial_read_handle_t readHandle, uint8_t *buffer, uint32_t length); + +#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U)) +/*! + * @brief Transmits data with the non-blocking mode. + * + * This is a non-blocking function, which returns directly without waiting for all data to be sent. + * When all data is sent, the module notifies the upper layer through a TX callback function and passes + * the status parameter @ref kStatus_SerialManager_Success. + * This function sends data using an interrupt method. The interrupt of the hardware could not be disabled. + * And There can only one buffer for transmission for the writing handle at the same time. + * + * @note The function #SerialManager_WriteBlocking and the function #SerialManager_WriteNonBlocking + * cannot be used at the same time. And, the TX callback is mandatory before the function could be used. + * + * @param writeHandle The serial manager module handle pointer. + * @param buffer Start address of the data to write. + * @param length Length of the data to write. + * @retval kStatus_SerialManager_Success Successfully sent all data. + * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all sent yet. + * @retval kStatus_SerialManager_Error An error occurred. + */ +serial_manager_status_t SerialManager_WriteNonBlocking(serial_write_handle_t writeHandle, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Reads data with the non-blocking mode. + * + * This is a non-blocking function, which returns directly without waiting for all data to be received. + * When all data is received, the module driver notifies the upper layer + * through a RX callback function and passes the status parameter @ref kStatus_SerialManager_Success. + * This function receives data using an interrupt method. The interrupt of the hardware could not be disabled. + * And There can only one buffer for receiving for the reading handle at the same time. + * + * @note The function #SerialManager_ReadBlocking and the function #SerialManager_ReadNonBlocking + * cannot be used at the same time. And, the RX callback is mandatory before the function could be used. + * + * @param readHandle The serial manager module handle pointer. + * @param buffer Start address of the data to store the received data. + * @param length The length of the data to be received. + * @retval kStatus_SerialManager_Success Successfully received all data. + * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all received yet. + * @retval kStatus_SerialManager_Error An error occurred. + */ +serial_manager_status_t SerialManager_ReadNonBlocking(serial_read_handle_t readHandle, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Tries to read data. + * + * The function tries to read data from internal ring buffer. If the ring buffer is not empty, the data will be + * copied from ring buffer to up layer buffer. The copied length is the minimum of the ring buffer and up layer length. + * After the data is copied, the actual data length is passed by the parameter length. + * And There can only one buffer for receiving for the reading handle at the same time. + * + * @param readHandle The serial manager module handle pointer. + * @param buffer Start address of the data to store the received data. + * @param length The length of the data to be received. + * @param receivedLength Length received from the ring buffer directly. + * @retval kStatus_SerialManager_Success Successfully received all data. + * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all received yet. + * @retval kStatus_SerialManager_Error An error occurred. + */ +serial_manager_status_t SerialManager_TryRead(serial_read_handle_t readHandle, + uint8_t *buffer, + uint32_t length, + uint32_t *receivedLength); + +/*! + * @brief Cancels unfinished send transmission. + * + * The function cancels unfinished send transmission. When the transfer is canceled, the module notifies the upper layer + * through a TX callback function and passes the status parameter @ref kStatus_SerialManager_Canceled. + * + * @note The function #SerialManager_CancelWriting cannot be used to abort the transmission of + * the function #SerialManager_WriteBlocking. + * + * @param writeHandle The serial manager module handle pointer. + * @retval kStatus_SerialManager_Success Get successfully abort the sending. + * @retval kStatus_SerialManager_Error An error occurred. + */ +serial_manager_status_t SerialManager_CancelWriting(serial_write_handle_t writeHandle); + +/*! + * @brief Cancels unfinished receive transmission. + * + * The function cancels unfinished receive transmission. When the transfer is canceled, the module notifies the upper + * layer + * through a RX callback function and passes the status parameter @ref kStatus_SerialManager_Canceled. + * + * @note The function #SerialManager_CancelReading cannot be used to abort the transmission of + * the function #SerialManager_ReadBlocking. + * + * @param readHandle The serial manager module handle pointer. + * @retval kStatus_SerialManager_Success Get successfully abort the receiving. + * @retval kStatus_SerialManager_Error An error occurred. + */ +serial_manager_status_t SerialManager_CancelReading(serial_read_handle_t readHandle); + +/*! + * @brief Installs a TX callback and callback parameter. + * + * This function is used to install the TX callback and callback parameter for the serial manager module. + * When any status of TX transmission changed, the driver will notify the upper layer by the installed callback + * function. And the status is also passed as status parameter when the callback is called. + * + * @param writeHandle The serial manager module handle pointer. + * @param callback The callback function. + * @param callbackParam The parameter of the callback function. + * @retval kStatus_SerialManager_Success Successfully install the callback. + */ +serial_manager_status_t SerialManager_InstallTxCallback(serial_write_handle_t writeHandle, + serial_manager_callback_t callback, + void *callbackParam); + +/*! + * @brief Installs a RX callback and callback parameter. + * + * This function is used to install the RX callback and callback parameter for the serial manager module. + * When any status of RX transmission changed, the driver will notify the upper layer by the installed callback + * function. And the status is also passed as status parameter when the callback is called. + * + * @param readHandle The serial manager module handle pointer. + * @param callback The callback function. + * @param callbackParam The parameter of the callback function. + * @retval kStatus_SerialManager_Success Successfully install the callback. + */ +serial_manager_status_t SerialManager_InstallRxCallback(serial_read_handle_t readHandle, + serial_manager_callback_t callback, + void *callbackParam); + +#endif + +/*! + * @brief Prepares to enter low power consumption. + * + * This function is used to prepare to enter low power consumption. + * + * @param serialHandle The serial manager module handle pointer. + * @retval kStatus_SerialManager_Success Successful operation. + */ +serial_manager_status_t SerialManager_EnterLowpower(serial_handle_t serialHandle); + +/*! + * @brief Restores from low power consumption. + * + * This function is used to restore from low power consumption. + * + * @param serialHandle The serial manager module handle pointer. + * @retval kStatus_SerialManager_Success Successful operation. + */ +serial_manager_status_t SerialManager_ExitLowpower(serial_handle_t serialHandle); + +#if defined(__cplusplus) +} +#endif +/*! @} */ +#endif /* __SERIAL_MANAGER_H__ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_port_uart.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_port_uart.h new file mode 100755 index 000000000..24a717009 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_port_uart.h @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SERIAL_PORT_UART_H__ +#define __SERIAL_PORT_UART_H__ + +/*! + * @addtogroup serial_port_uart + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief serial port uart handle size*/ +#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U)) +#define SERIAL_PORT_UART_HANDLE_SIZE (166U) +#else +#define SERIAL_PORT_UART_HANDLE_SIZE (4U) +#endif + +/*! @brief serial port uart parity mode*/ +typedef enum _serial_port_uart_parity_mode +{ + kSerialManager_UartParityDisabled = 0x0U, /*!< Parity disabled */ + kSerialManager_UartParityEven = 0x1U, /*!< Parity even enabled */ + kSerialManager_UartParityOdd = 0x2U, /*!< Parity odd enabled */ +} serial_port_uart_parity_mode_t; + +/*! @brief serial port uart stop bit count*/ +typedef enum _serial_port_uart_stop_bit_count +{ + kSerialManager_UartOneStopBit = 0U, /*!< One stop bit */ + kSerialManager_UartTwoStopBit = 1U, /*!< Two stop bits */ +} serial_port_uart_stop_bit_count_t; + +/*! @brief serial port uart config struct*/ +typedef struct _serial_port_uart_config +{ + uint32_t clockRate; /*!< clock rate */ + uint32_t baudRate; /*!< baud rate */ + serial_port_uart_parity_mode_t parityMode; /*!< Parity mode, disabled (default), even, odd */ + serial_port_uart_stop_bit_count_t stopBitCount; /*!< Number of stop bits, 1 stop bit (default) or 2 stop bits */ + uint8_t instance; /*!< Instance (0 - UART0, 1 - UART1, ...), detail information + please refer to the SOC corresponding RM. */ + uint8_t enableRx; /*!< Enable RX */ + uint8_t enableTx; /*!< Enable TX */ +} serial_port_uart_config_t; +/*! @} */ +#endif /* __SERIAL_PORT_UART_H__ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_port_usb.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_port_usb.h new file mode 100755 index 000000000..fc1dd000e --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/include/serial_port_usb.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 - 2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SERIAL_PORT_USB_H__ +#define __SERIAL_PORT_USB_H__ + +#if defined(FSL_RTOS_FREE_RTOS) +#include "FreeRTOS.h" +#endif + +/*! + * @addtogroup serial_port_usb + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief serial port usb handle size*/ +#define SERIAL_PORT_USB_CDC_HANDLE_SIZE (72) + +/*! @brief USB interrupt priority*/ +#if defined(__GIC_PRIO_BITS) +#define USB_DEVICE_INTERRUPT_PRIORITY (25U) +#else +#if defined(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY) +#define USB_DEVICE_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY) +#else +/* The default value 3 is used to support different ARM Core, such as CM0P, CM4, CM7, and CM33, etc. + * The minimum number of priority bits implemented in the NVIC is 2 on these SOCs. The value of mininum + * priority is 3 (2^2 - 1). So, the default value is 3. + */ +#define USB_DEVICE_INTERRUPT_PRIORITY (3U) +#endif +#endif + +/*! @brief USB controller ID */ +typedef enum _serial_port_usb_cdc_controller_index +{ + kSerialManager_UsbControllerKhci0 = 0U, /*!< KHCI 0U */ + kSerialManager_UsbControllerKhci1 = 1U, /*!< KHCI 1U, Currently, there are no platforms which have two KHCI IPs, + this is reserved to be used in the future. */ + kSerialManager_UsbControllerEhci0 = 2U, /*!< EHCI 0U */ + kSerialManager_UsbControllerEhci1 = 3U, /*!< EHCI 1U, Currently, there are no platforms which have two EHCI IPs, + this is reserved to be used in the future. */ + + kSerialManager_UsbControllerLpcIp3511Fs0 = 4U, /*!< LPC USB IP3511 FS controller 0 */ + kSerialManager_UsbControllerLpcIp3511Fs1 = 5U, /*!< LPC USB IP3511 FS controller 1, there are no platforms which + have two IP3511 IPs, this is reserved to be used in the future. */ + + kSerialManager_UsbControllerLpcIp3511Hs0 = 6U, /*!< LPC USB IP3511 HS controller 0 */ + kSerialManager_UsbControllerLpcIp3511Hs1 = 7U, /*!< LPC USB IP3511 HS controller 1, there are no platforms which + have two IP3511 IPs, this is reserved to be used in the future. */ + + kSerialManager_UsbControllerOhci0 = 8U, /*!< OHCI 0U */ + kSerialManager_UsbControllerOhci1 = 9U, /*!< OHCI 1U, Currently, there are no platforms which have two OHCI IPs, + this is reserved to be used in the future. */ + + kSerialManager_UsbControllerIp3516Hs0 = 10U, /*!< IP3516HS 0U */ + kSerialManager_UsbControllerIp3516Hs1 = 11U, /*!< IP3516HS 1U, Currently, there are no platforms which have two + IP3516HS IPs, this is reserved to be used in the future. */ +} serial_port_usb_cdc_controller_index_t; + +/*! @brief serial port usb config struct*/ +typedef struct _serial_port_usb_cdc_config +{ + serial_port_usb_cdc_controller_index_t controllerIndex; /*!< controller index */ +} serial_port_usb_cdc_config_t; + +/*! @} */ +#endif /* __SERIAL_PORT_USB_H__ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/Makefile b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/Makefile new file mode 100755 index 000000000..6d38bf1de --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fsl_lpspi.c lpspi_interrupt.c connect_flash_spi.c flexspi_nor_flash_ops.c flexspi_nor_polling_transfer.c fsl_flexspi.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/app.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/app.h new file mode 100755 index 000000000..c74f6ba10 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/app.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _APP_H_ +#define _APP_H_ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*${macro:start}*/ +#define EXAMPLE_FLEXSPI FLEXSPI +#define FLASH_SIZE 0x2000 /* 64Mb/KByte */ +#define EXAMPLE_FLEXSPI_AMBA_BASE FlexSPI_AMBA_BASE +#define FLASH_PAGE_SIZE 256 +#define EXAMPLE_SECTOR 0 +#define SECTOR_SIZE 0x1000 /* 4K */ +#define EXAMPLE_FLEXSPI_CLOCK kCLOCK_FlexSpi + +#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 7 +#define NOR_CMD_LUT_SEQ_IDX_READ_FAST 13 +#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 0 +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS 1 +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 2 +#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 3 +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE 6 +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 4 +#define NOR_CMD_LUT_SEQ_IDX_READID 8 +#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 9 +#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 +#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 11 +#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 12 +#define NOR_CMD_LUT_SEQ_IDX_ERASECHIP 5 + +#define CUSTOM_LUT_LENGTH 60 +#define FLASH_QUAD_ENABLE 0x40 +#define FLASH_BUSY_STATUS_POL 1 +#define FLASH_BUSY_STATUS_OFFSET 0 + +/*${macro:end}*/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*${prototype:start}*/ +void BOARD_InitHardware(void); + +static inline void flexspi_clock_init(void) +{ + const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U}; + + CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll); + CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 24); /* Set PLL3 PFD0 clock 360MHZ. */ + CLOCK_SetMux(kCLOCK_FlexspiMux, 0x3); /* Choose PLL3 PFD0 clock as flexspi source clock. */ + CLOCK_SetDiv(kCLOCK_FlexspiDiv, 2); /* flexspi clock 120M. */ +} +/*${prototype:end}*/ + +#endif /* _APP_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/connect_flash_spi.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/connect_flash_spi.c new file mode 100755 index 000000000..f1380dce1 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/connect_flash_spi.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-27 SummerGift add spi flash port file + */ + +/** +* @file connect_flash_spi.c +* @brief support stm32f407-st-discovery-board spi flash function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: connect_flash_spi.c +Description: support stm32f407-st-discovery-board spi flash bus register function +Others: take RT-Thread v4.0.2/bsp/stm32/stm32f407-atk-explorer/board/ports/spi-flash-init.c + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. support stm32f407-st-discovery-board spi flash register to spi bus +2. support stm32f407-st-discovery-board spi flash init +*************************************************/ + +//#include "connect_spi.h" +#include "flash_spi.h" + +int FlashW25qxxSpiDeviceInit(void) +{ +#ifdef BSP_USING_SPI1 + +// __IO uint32_t tmpreg = 0x00U; +// RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; +// tmpreg = RCC->AHB1ENR & RCC_AHB1ENR_GPIOBEN; +// (void)tmpreg; +// +// if (EOK != HwSpiDeviceAttach(SPI_BUS_NAME_1, "spi1_dev0", GPIOB, GPIO_Pin_0)) { +// return ERROR; +// } +// +// if (NONE == SpiFlashInit(SPI_BUS_NAME_1, "spi1_dev0", SPI_1_DRV_NAME, "spi1_W25Q64")) { +// return ERROR; +// } + +#endif + + return EOK; +} \ No newline at end of file diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/connect_spi.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/connect_spi.c new file mode 100755 index 000000000..5366f58e8 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/connect_spi.c @@ -0,0 +1,1639 @@ +/* + * Copyright (c) 2020 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-5 SummerGift first version + * 2018-12-11 greedyhao Porting for stm32f7xx + * 2019-01-03 zylx modify DMA initialization and spixfer function + * 2020-01-15 whj4674672 Porting for stm32h7xx + * 2020-06-18 thread-liu Porting for stm32mp1xx + * 2020-10-14 Dozingfiretruck Porting for stm32wbxx + */ + +/** +* @file connect_spi.c +* @brief support stm32f407-st-discovery-board spi function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +/************************************************* +File name: connect_spi.c +Description: support stm32f407-st-discovery-board spi configure and spi bus register function +Others: take RT-Thread v4.0.2/bsp/stm32/libraries/HAL_Drivers/drv_spi.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. support stm32f407-st-discovery-board spi configure, write and read +2. support stm32f407-st-discovery-board spi bus device and driver register +*************************************************/ + +#include "stm32f4xx.h" +#include "connect_spi.h" +#include "board.h" +#include "misc.h" +#include "hardware_spi.h" +#include "hardware_dma.h" +#include "hardware_gpio.h" +#include "hardware_rcc.h" + +#include +#include + +/* SPI GPIO define */ +#ifdef BSP_USING_SPI1 +#define SPI1_GPIO_NSS GPIO_Pin_4 +#define SPI1_NSS_PIN_SOURCE GPIO_PinSource4 +#define SPI1_GPIO_SCK GPIO_Pin_5 +#define SPI1_SCK_PIN_SOURCE GPIO_PinSource5 +#define SPI1_GPIO_MISO GPIO_Pin_6 +#define SPI1_MISO_PIN_SOURCE GPIO_PinSource6 +#define SPI1_GPIO_MOSI GPIO_Pin_7 +#define SPI1_MOSI_PIN_SOURCE GPIO_PinSource7 +#define SPI1_GPIO GPIOA +#define SPI1_GPIO_RCC RCC_AHB1Periph_GPIOA +#define RCC_APBPeriph_SPI1 RCC_APB2Periph_SPI1 +#endif + +#ifdef BSP_USING_SPI2 +#define SPI2_GPIO_NSS GPIO_Pin_6 +#define SPI2_NSS_PIN_SOURCE GPIO_PinSource6 +#define SPI2_GPIO_SCK GPIO_Pin_13 +#define SPI2_SCK_PIN_SOURCE GPIO_PinSource13 +#define SPI2_GPIO_MISO GPIO_Pin_2 +#define SPI2_MISO_PIN_SOURCE GPIO_PinSource2 +#define SPI2_GPIO_MOSI GPIO_Pin_3 +#define SPI2_MOSI_PIN_SOURCE GPIO_PinSource3 +#define SPI2_GPIO GPIOC +#define SPI2_SCK GPIOB +#define SPI2_GPIO_RCC RCC_AHB1Periph_GPIOC +#define SPI2_GPIO_RCC_SCK RCC_AHB1Periph_GPIOB +#define RCC_APBPeriph_SPI2 RCC_APB1Periph_SPI2 +#endif + +#ifdef BSP_USING_SPI3 +#define SPI3_GPIO_NSS GPIO_Pin_15 +#define SPI3_NSS_PIN_SOURCE GPIO_PinSource15 +#define SPI3_GPIO_SCK GPIO_Pin_10 +#define SPI3_SCK_PIN_SOURCE GPIO_PinSource10 +#define SPI3_GPIO_MISO GPIO_Pin_11 +#define SPI3_MISO_PIN_SOURCE GPIO_PinSource11 +#define SPI3_GPIO_MOSI GPIO_Pin_12 +#define SPI3_MOSI_PIN_SOURCE GPIO_PinSource12 +#define SPI3_GPIO GPIOC +#define SPI3_NSS GPIOA +#define SPI3_GPIO_RCC RCC_AHB1Periph_GPIOC +#define SPI3_GPIO_RCC_NSS RCC_AHB1Periph_GPIOA +#define RCC_APBPeriph_SPI3 RCC_APB2Periph_SPI3 +#endif + +/** + * This function SPI device initialization + * + * @param spi_drv SPI device structure pointer + * + * @param cfg SPI device operating mode configuration structure pointer + * + * @return if successful return EOK + */ + +static x_err_t Stm32SpiInit(struct Stm32Spi *spi_drv, struct SpiMasterParam *cfg) +{ + NULL_PARAM_CHECK(spi_drv); + NULL_PARAM_CHECK(cfg); + + SPI_InitTypeDef *spi_init = &spi_drv->init; + + if (cfg->spi_work_mode & DEV_SPI_SLAVE){ + spi_init->SPI_Mode = SPI_Mode_Slave; + } + else{ + spi_init->SPI_Mode = SPI_Mode_Master; + } + + if (cfg->spi_work_mode & SPI_3WIRE){ + spi_init->SPI_Direction = SPI_Direction_1Line_Rx; + } + else{ + spi_init->SPI_Direction = SPI_Direction_2Lines_FullDuplex; + } + + if (cfg->spi_data_bit_width == 8){ + spi_init->SPI_DataSize = SPI_DataSize_8b; + } + else if (cfg->spi_data_bit_width == 16){ + spi_init->SPI_DataSize = SPI_DataSize_16b; + } + else{ + return EPIO; + } + + if (cfg->spi_work_mode & SPI_LINE_CPHA){ + spi_init->SPI_CPHA = SPI_CPHA_2Edge; + } + else { + spi_init->SPI_CPHA = SPI_CPHA_1Edge; + } + + if (cfg->spi_work_mode & SPI_LINE_CPOL) { + spi_init->SPI_CPOL = SPI_CPOL_High; + } + else{ + spi_init->SPI_CPOL = SPI_CPOL_Low; + } + + if (cfg->spi_work_mode & SPI_NO_CS) { + spi_init->SPI_NSS = SPI_NSS_Soft; + } + else{ + spi_init->SPI_NSS = SPI_NSS_Soft; + } + + uint32_t SPI_APB_CLOCK; + + SPI_APB_CLOCK = system_core_clock>>apb_presc_table[(RCC->CFGR & RCC_CFGR_PPRE2)>> 13U]; + + if (cfg->spi_maxfrequency >= SPI_APB_CLOCK / 2){ + spi_init->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; + } + else if (cfg->spi_maxfrequency >= SPI_APB_CLOCK / 4){ + spi_init->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; + } + else if (cfg->spi_maxfrequency >= SPI_APB_CLOCK / 8){ + spi_init->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; + } + else if (cfg->spi_maxfrequency >= SPI_APB_CLOCK / 16){ + spi_init->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; + } + else if (cfg->spi_maxfrequency >= SPI_APB_CLOCK / 32){ + spi_init->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; + } + else if (cfg->spi_maxfrequency >= SPI_APB_CLOCK / 64){ + spi_init->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; + } + else if (cfg->spi_maxfrequency >= SPI_APB_CLOCK / 128) { + spi_init->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; + } + else { + /* min prescaler 256 */ + spi_init->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; + } + RCC_ClocksTypeDef RCC_ClocksStatus; + RCC_GetClocksFreq(&RCC_ClocksStatus); + + if (cfg->spi_work_mode & SPI_MSB){ + spi_init->SPI_FirstBit = SPI_FirstBit_MSB; /*Highest bit transmit first*/ + } + else{ + spi_init->SPI_FirstBit = SPI_FirstBit_LSB; /*lowest bit transmit first*/ + } + + spi_init->SPI_CRCPolynomial = 7; + + SPI_Init(spi_drv->instance, spi_init); + + SPI_Cmd(spi_drv->instance, ENABLE); + + uint32_t prioritygroup = 0x00U; + /* DMA configuration */ + if (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG){ + DMA_Init(spi_drv->dma.dma_rx.instance, &spi_drv->dma.dma_rx.init); + + prioritygroup = NVIC_GetPriorityGrouping(); + + NVIC_SetPriority(spi_drv->dma.dma_rx.dma_irq, NVIC_EncodePriority(prioritygroup, 0, 0)); + + NVIC_EnableIRQ(spi_drv->dma.dma_rx.dma_irq); + } + + if (spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG){ + DMA_Init(spi_drv->dma.dma_tx.instance, &spi_drv->dma.dma_tx.init); + + prioritygroup = NVIC_GetPriorityGrouping(); + + NVIC_SetPriority(spi_drv->dma.dma_tx.dma_irq, NVIC_EncodePriority(prioritygroup, 0, 1)); + + NVIC_EnableIRQ(spi_drv->dma.dma_tx.dma_irq); + } + + spi_drv->instance->CR1 |= SPI_CR1_SPE; + + return EOK; +} + +static void DmaSpiConfig(struct SpiBus *spi_bus, uint32_t setting_len, void *rx_base_addr, void *tx_base_addr) +{ + struct Stm32Spi *spi = (struct Stm32Spi *)spi_bus->private_data; + uint32 tmpreg = 0x00U; + NVIC_InitTypeDef NVIC_InitStructure; + + if(spi->spi_dma_flag & SPI_USING_RX_DMA_FLAG) + { + spi->dma.dma_rx.setting_len = setting_len; + DMA_DeInit(spi->dma.dma_rx.instance); + while(DMA_GetCmdStatus(spi->dma.dma_rx.instance) != DISABLE); + spi->dma.dma_rx.init.DMA_Channel = spi->dma.dma_rx.channel; + spi->dma.dma_rx.init.DMA_PeripheralBaseAddr = (uint32_t)&(spi->instance->DR); + spi->dma.dma_rx.init.DMA_Memory0BaseAddr = (uint32_t)rx_base_addr; + spi->dma.dma_rx.init.DMA_DIR = DMA_DIR_PeripheralToMemory; + spi->dma.dma_rx.init.DMA_BufferSize = spi->dma.dma_rx.setting_len; + spi->dma.dma_rx.init.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + spi->dma.dma_rx.init.DMA_MemoryInc = DMA_MemoryInc_Enable; + spi->dma.dma_rx.init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + spi->dma.dma_rx.init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + spi->dma.dma_rx.init.DMA_Mode = DMA_Mode_Normal; + spi->dma.dma_rx.init.DMA_Priority = DMA_Priority_High; + spi->dma.dma_rx.init.DMA_FIFOMode = DMA_FIFOMode_Disable; + spi->dma.dma_rx.init.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + spi->dma.dma_rx.init.DMA_MemoryBurst = DMA_MemoryBurst_INC4; + spi->dma.dma_rx.init.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4; + DMA_Init(spi->dma.dma_rx.instance, &spi->dma.dma_rx.init); + DMA_ITConfig(spi->dma.dma_rx.instance, DMA_IT_TC, ENABLE); + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); + + DMA_Cmd(spi->dma.dma_rx.instance, ENABLE); + + NVIC_InitStructure.NVIC_IRQChannel = spi->dma.dma_rx.dma_irq; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + tmpreg = 0x00U; + RCC->AHB1ENR |= spi->dma.dma_rx.dma_rcc; + tmpreg = RCC->AHB1ENR & spi->dma.dma_rx.dma_rcc; + (void)tmpreg; + } + + if(spi->spi_dma_flag & SPI_USING_TX_DMA_FLAG) + { + spi->dma.dma_tx.setting_len = setting_len; + DMA_DeInit(spi->dma.dma_tx.instance); + while(DMA_GetCmdStatus(spi->dma.dma_tx.instance) != DISABLE); + spi->dma.dma_tx.init.DMA_PeripheralBaseAddr = (uint32_t)&(spi->instance->DR); + spi->dma.dma_tx.init.DMA_Memory0BaseAddr = (uint32_t)tx_base_addr; + spi->dma.dma_tx.init.DMA_DIR = DMA_DIR_MemoryToPeripheral; + spi->dma.dma_tx.init.DMA_BufferSize = spi->dma.dma_tx.setting_len; + spi->dma.dma_tx.init.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + spi->dma.dma_tx.init.DMA_MemoryInc = DMA_MemoryInc_Enable; + spi->dma.dma_tx.init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + spi->dma.dma_tx.init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + spi->dma.dma_tx.init.DMA_Mode = DMA_Mode_Normal; + spi->dma.dma_tx.init.DMA_Priority = DMA_Priority_Low; + spi->dma.dma_tx.init.DMA_FIFOMode = DMA_FIFOMode_Disable; + spi->dma.dma_tx.init.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + spi->dma.dma_tx.init.DMA_MemoryBurst = DMA_MemoryBurst_INC4; + spi->dma.dma_tx.init.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4; + DMA_Init(spi->dma.dma_tx.instance, &spi->dma.dma_tx.init); + DMA_ITConfig(spi->dma.dma_tx.instance, DMA_IT_TC, ENABLE); + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); + + DMA_Cmd(spi->dma.dma_tx.instance, ENABLE); + + NVIC_InitStructure.NVIC_IRQChannel = spi->dma.dma_tx.dma_irq; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + tmpreg = 0x00U; + RCC->AHB1ENR |= spi->dma.dma_rx.dma_rcc; + tmpreg = RCC->AHB1ENR & spi->dma.dma_rx.dma_rcc; + (void)tmpreg; + } +} + + +static void DmaRxDoneIsr(struct SpiBus *spi_bus) +{ + struct Stm32Spi *spi = (struct Stm32Spi *) spi_bus->bus.private_data; + x_size_t recv_len; + x_base level; + + if (DMA_GetFlagStatus(spi->dma.dma_rx.instance, spi->spi_dma_flag) != RESET) + { + level = CriticalAreaLock(); + + recv_len = spi->dma.dma_rx.setting_len - spi->dma.dma_rx.last_index; + spi->dma.dma_rx.last_index = 0; + CriticalAreaUnLock(level); + DMA_ClearFlag(spi->dma.dma_rx.instance, spi->spi_dma_flag); + } +} + + +static void DmaTxDoneIsr(struct SpiBus *spi_bus) +{ + struct Stm32Spi *spi = (struct Stm32Spi *) spi_bus->bus.private_data; + x_size_t send_len; + x_base level; + + if (DMA_GetFlagStatus(spi->dma.dma_tx.instance, spi->spi_dma_flag) != RESET) + { + level = CriticalAreaLock(); + + send_len = spi->dma.dma_tx.setting_len - spi->dma.dma_tx.last_index; + spi->dma.dma_tx.last_index = 0; + CriticalAreaUnLock(level); + DMA_ClearFlag(spi->dma.dma_tx.instance, spi->spi_dma_flag); + } +} + + +static int SpiWaitUntilTimeout(SPI_InitTypeDef spi_init, SPI_TypeDef *spi_instance, uint32_t flag, uint32_t state, uint32_t time_out, uint32_t tick_start) +{ + while((((spi_instance->SR & flag) == (flag)) ? SET : RESET) != state) + { + if(time_out != 0xFFFFFFFFU) + { + if((time_out == 0U) || ((CurrentTicksGain() * 1000 / TICK_PER_SECOND-tick_start) >= time_out)) + { + spi_instance->CR2 &= (~(SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR)); + + if((spi_init.SPI_Mode == SPI_Mode_Master)&&((spi_init.SPI_Direction == SPI_Direction_1Line_Rx)||(spi_init.SPI_Direction == SPI_Direction_2Lines_RxOnly))) { + /* Disable SPI peripheral */ + spi_instance->CR1 &= (~SPI_CR1_SPE); + } + + return 3; + } + } + } + return 0; +} +/** + * This function SPI sends data through DMA + * + * @param spi_init SPI Init structure + * + * @param spi_instance SPI control handle + * + * @param dma_init DMA Init structure + * + * @param dma_instance DMA Controller + * + * @param p_data Send data buffer address + * + * @param size Amount of data sent + * + * @return if successful return EOK + */ +int SpiTransmitDma(SPI_InitTypeDef spi_init, SPI_TypeDef *spi_instance, DMA_InitTypeDef dma_init, DMA_Stream_TypeDef *dma_instance, uint8_t *p_data, uint16_t size) +{ + int errorcode = 0; + __IO uint16_t tx_xfer_count; + uint8_t *p_txbuff_ptr; + uint16_t tx_xfer_size; + + if((p_data == NONE) || (size == 0)){ + errorcode = 1; + goto error; + } + + tx_xfer_count = size; + p_txbuff_ptr = (uint8_t *)p_data; + tx_xfer_size = size; + + /* Configure communication direction : 1Line */ + if(spi_init.SPI_Direction == SPI_Direction_1Line_Rx){ + spi_instance->CR1 |= SPI_CR1_BIDIOE; + } + + /* Clear DBM bit */ + dma_instance->CR &= (uint32_t)(~DMA_SxCR_DBM); + + /* Configure DMA Stream data length */ + dma_instance->NDTR = tx_xfer_count; + + /* Memory to Peripheral */ + if((dma_init.DMA_DIR) == DMA_DIR_MemoryToPeripheral) + { + /* Configure DMA Stream destination address */ + dma_instance->PAR = spi_instance->DR; + + /* Configure DMA Stream source address */ + dma_instance->M0AR = *p_txbuff_ptr; + } + /* Peripheral to Memory */ + else + { + /* Configure DMA Stream source address */ + dma_instance->PAR = *p_txbuff_ptr; + + /* Configure DMA Stream destination address */ + dma_instance->M0AR = spi_instance->DR; + } + + /* Enable Common interrupts*/ + dma_instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME | DMA_IT_HT; + dma_instance->FCR |= DMA_IT_FE; + dma_instance->CR |= DMA_SxCR_EN; + + /* Check if the SPI is already enabled */ + if((spi_instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE){ + /* Enable SPI peripheral */ + spi_instance->CR1 |= SPI_CR1_SPE; + } + + /* Enable the SPI Error Interrupt Bit */ + spi_instance->CR2 |= SPI_CR2_ERRIE; + + /* Enable Tx DMA Request */ + spi_instance->CR2 |=SPI_CR2_TXDMAEN; + +error : + return errorcode; +} +/** + * This function SPI carries out duplex communication through DMA + * + * @param spi_init SPI Init structure + * + * @param spi_instance SPI control handle + * + * @param dmarx_init DMA Init structure---Rx + * + * @param dmarx_instance DMA Controller + * + * @param dmatx_init DMA Init structure---Tx + * + * @param dmatx_instance DMA Controller + * + * @param p_txdata Send data buffer address + * + * @param p_rxdata Receive data buffer address + * + * @param size Amount of data + * + * @return if successful return EOK + */ +int SpiTransmitreceiveDma(SPI_InitTypeDef spi_init, SPI_TypeDef *spi_instance, DMA_InitTypeDef dmarx_init, DMA_Stream_TypeDef *dmarx_instance, DMA_InitTypeDef dmatx_init, DMA_Stream_TypeDef *dmatx_instance, uint8_t *p_txdata, uint8_t *p_rxdata, uint16_t size) +{ + uint32_t tmp = 0U; + int errorcode = 0; + __IO uint16_t tx_xfer_count; + __IO uint16_t rx_xfer_count; + uint8_t *p_txbuff_ptr; + uint8_t *p_rxbuff_ptr; + uint16_t tx_xfer_size; + uint16_t rx_xfer_size; + + tmp = spi_init.SPI_Mode; + if(!((tmp == SPI_Mode_Master) && (spi_init.SPI_Direction == SPI_Direction_2Lines_FullDuplex))) + { + errorcode = 2; + goto error; + } + + if((p_txdata == NONE ) || (p_rxdata == NONE ) || (size == 0)) + { + errorcode = 1; + goto error; + } + + /* Set the transaction information */ + p_txbuff_ptr = (uint8_t*)p_txdata; + tx_xfer_size = size; + tx_xfer_count = size; + p_rxbuff_ptr = (uint8_t*)p_rxdata; + rx_xfer_size = size; + rx_xfer_count = size; + + /* Clear DBM bit */ + dmarx_instance->CR &= (uint32_t)(~DMA_SxCR_DBM); + + /* Configure DMA Stream data length */ + dmarx_instance->NDTR = rx_xfer_count; + + /* Memory to Peripheral */ + if((dmarx_init.DMA_DIR) == DMA_DIR_MemoryToPeripheral) + { + /* Configure DMA Stream destination address */ + dmarx_instance->PAR = spi_instance->DR; + + /* Configure DMA Stream source address */ + dmarx_instance->M0AR = *p_rxbuff_ptr; + } + /* Peripheral to Memory */ + else + { + /* Configure DMA Stream source address */ + dmarx_instance->PAR = *p_rxbuff_ptr; + + /* Configure DMA Stream destination address */ + dmarx_instance->M0AR = spi_instance->DR; + } + + /* Enable Common interrupts*/ + dmarx_instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME | DMA_IT_HT; + dmarx_instance->FCR |= DMA_IT_FE; + dmarx_instance->CR |= DMA_SxCR_EN; + + /* Enable Rx DMA Request */ + spi_instance->CR2 |= SPI_CR2_RXDMAEN; + + /* Clear DBM bit */ + dmatx_instance->CR &= (uint32_t)(~DMA_SxCR_DBM); + + /* Configure DMA Stream data length */ + dmatx_instance->NDTR = tx_xfer_count; + + /* Memory to Peripheral */ + if((dmatx_init.DMA_DIR) == DMA_DIR_MemoryToPeripheral) + { + /* Configure DMA Stream destination address */ + dmatx_instance->PAR = spi_instance->DR; + + /* Configure DMA Stream source address */ + dmatx_instance->M0AR = *p_txbuff_ptr; + } + /* Peripheral to Memory */ + else{ + /* Configure DMA Stream source address */ + dmatx_instance->PAR = *p_txbuff_ptr; + + /* Configure DMA Stream destination address */ + dmatx_instance->M0AR = spi_instance->DR; + } + + /* Enable Common interrupts*/ + dmatx_instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME | DMA_IT_HT; + dmatx_instance->FCR |= DMA_IT_FE; + dmatx_instance->CR |= DMA_SxCR_EN; + + /* Check if the SPI is already enabled */ + if((spi_instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE){ + /* Enable SPI peripheral */ + spi_instance->CR1 |= SPI_CR1_SPE; + } + /* Enable the SPI Error Interrupt Bit */ + spi_instance->CR2 |= SPI_CR2_ERRIE; + + /* Enable Tx DMA Request */ + spi_instance->CR2 |= SPI_CR2_TXDMAEN; + +error : + return errorcode; +} +/** + * This function SPI receives data through DMA + * + * @param spi_init SPI Init structure + * + * @param spi_instance SPI control handle + * + * @param dmarx_init DMA Init structure---Rx + * + * @param dmarx_instance DMA Controller + * + * @param dmatx_init DMA Init structure---Tx + * + * @param dmatx_instance DMA Controller + * + * @param p_data Receive data buffer address + * + * @param size Amount of data + * + * @return if successful return EOK + */ +int SpiReceiveDma(SPI_InitTypeDef spi_init, SPI_TypeDef *spi_instance, DMA_InitTypeDef dmarx_init, DMA_Stream_TypeDef *dmarx_instance, DMA_InitTypeDef dmatx_init, DMA_Stream_TypeDef *dmatx_instance, uint8_t *p_data, uint16_t size) +{ + int errorcode = 0; + __IO uint16_t rx_xfer_count; + uint8_t *p_rxbuff_ptr; + uint16_t rx_xfer_size; + + if((spi_init.SPI_Direction == SPI_Direction_2Lines_FullDuplex)&&(spi_init.SPI_Mode == SPI_Mode_Master)) { + /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */ + return SpiTransmitreceiveDma(spi_init, spi_instance, dmarx_init, dmarx_instance, dmatx_init, dmatx_instance, p_data, p_data, size); + } + + if((p_data == NONE) || (size == 0)) + { + errorcode = 1; + goto error; + } + + rx_xfer_count = size; + rx_xfer_size = size; + p_rxbuff_ptr = (uint8_t *)p_data; + + /* Configure communication direction : 1Line */ + if(spi_init.SPI_Direction == SPI_Direction_1Line_Rx) { + spi_instance->CR1 &= (~SPI_CR1_BIDIOE); + } + /* Clear DBM bit */ + dmarx_instance->CR &= (uint32_t)(~DMA_SxCR_DBM); + + /* Configure DMA Stream data length */ + dmarx_instance->NDTR = rx_xfer_count; + + /* Memory to Peripheral */ + if((dmarx_init.DMA_DIR) == DMA_DIR_MemoryToPeripheral){ + /* Configure DMA Stream destination address */ + dmarx_instance->PAR = spi_instance->DR; + /* Configure DMA Stream source address */ + dmarx_instance->M0AR = *p_rxbuff_ptr; + } + /* Peripheral to Memory */ + else + { + /* Configure DMA Stream source address */ + dmarx_instance->PAR = *p_rxbuff_ptr; + + /* Configure DMA Stream destination address */ + dmarx_instance->M0AR = spi_instance->DR; + } + + /* Enable Common interrupts*/ + dmarx_instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME | DMA_IT_HT; + dmarx_instance->FCR |= DMA_IT_FE; + dmarx_instance->CR |= DMA_SxCR_EN; + + /* Check if the SPI is already enabled */ + if((spi_instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE){ + /* Enable SPI peripheral */ + spi_instance->CR1 |= SPI_CR1_SPE; + } + + /* Enable the SPI Error Interrupt Bit */ + spi_instance->CR2 |= SPI_CR2_ERRIE; + + /* Enable Rx DMA Request */ + spi_instance->CR2 |= SPI_CR2_RXDMAEN; + +error: + return errorcode; +} +/** + * This function SPI receives data + * + * @param spi_init SPI Init structure + * + * @param spi_instance SPI control handle + * + * @param p_data Transmit data buffer address + * + * @param size Amount of data + * + * @param Timeout waiting time + * + * @return if successful return EOK + */ +int SpiTransmit(SPI_InitTypeDef spi_init, SPI_TypeDef *spi_instance, uint8_t *p_data, uint16_t size, uint32_t Timeout) +{ + uint32_t tickstart = 0U; + int errorcode = 0; + __IO uint16_t tx_xfer_count; + __IO uint32_t SPITimeout; + + /* Init tickstart for timeout management*/ + tickstart = CurrentTicksGain() * 1000 / TICK_PER_SECOND; + + if((p_data == NONE ) || (size == 0)){ + errorcode = 1; + goto error; + } + + tx_xfer_count = size; + + /* Configure communication direction : 1Line */ + if(spi_init.SPI_Direction == SPI_Direction_1Line_Rx){ + spi_instance->CR1 |= SPI_CR1_BIDIOE; + } + + /* Check if the SPI is already enabled */ + if((spi_instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE){ + /* Enable SPI peripheral */ + spi_instance->CR1 |= SPI_CR1_SPE; + } + + /* Transmit data in 16 Bit mode */ + if(spi_init.SPI_DataSize == SPI_DataSize_16b) + { + if((spi_init.SPI_Mode == SPI_Mode_Slave) || (tx_xfer_count == 0x01)){ + spi_instance->DR = *((uint16_t *)p_data); + + p_data += sizeof(uint16_t); + tx_xfer_count--; + } + /* Transmit data in 16 Bit mode */ + while (tx_xfer_count > 0U) + { + SPITimeout = 0x1000; + /* Wait until TXE flag is set to send data */ + while (SPI_I2S_GetFlagStatus(spi_instance, SPI_I2S_FLAG_TXE) == RESET) + { + if((SPITimeout--) == 0) { + KPrintf("spi time out\n"); + errorcode = 3; + goto error; + } + } + /* Write to the data register and write the data to be written into the transmit buffer */ + spi_instance->DR = *((uint16_t *)p_data); + + p_data += sizeof(uint16_t); + tx_xfer_count--; + } + } + /* Transmit data in 8 Bit mode */ + else + { + if((spi_init.SPI_Mode == SPI_Mode_Slave) || (tx_xfer_count == 0x01U)){ + *((__IO uint8_t*)&spi_instance->DR) = (*p_data); + + p_data += sizeof(uint8_t); + tx_xfer_count--; + } + + while(tx_xfer_count > 0) + { + SPITimeout = 0x1000; + + /* Wait for the send buffer to be empty, TXE event*/ + while (SPI_I2S_GetFlagStatus(spi_instance, SPI_I2S_FLAG_TXE) == RESET) + { + if((SPITimeout--) == 0){ + KPrintf("spi time out\n"); + errorcode = 3; + goto error; + } + } + + /* Write to the data register and write the data to be written into the transmit buffer*/ + *((__IO uint8_t*)&spi_instance->DR) = (*p_data); + + p_data += sizeof(uint8_t); + tx_xfer_count--; + } +} + + /* Wait until TXE flag */ + if(SpiWaitUntilTimeout(spi_init, spi_instance, SPI_FLAG_TXE, SET, Timeout, tickstart) != 0){ + errorcode = 3; + goto error; + } + + /* Check Busy flag */ + if(SpiWaitUntilTimeout(spi_init, spi_instance, SPI_FLAG_BSY, RESET, Timeout, tickstart) != 0){ + errorcode = 1; + goto error; + } + +error: + return errorcode; +} +/** + * This function SPI Transmit and receive + * + * @param spi_init SPI Init structure + * + * @param spi_instance SPI control handle + * + * @param p_txdata Transmit data buffer address + * + * @param p_rxdata receive data buffer address + * + * @param size Amount of data + * + * @param Timeout waiting time + * + * @return if successful return EOK + */ +int SpiTransmitreceive(SPI_InitTypeDef spi_init, SPI_TypeDef *spi_instance, uint8_t *p_txdata, uint8_t *p_rxdata, uint16_t size, uint32_t Timeout) +{ + uint32_t tmp = 0U; + + uint32_t tickstart = 0U; + /* Variable used to alternate Rx and Tx during transfer */ + uint32_t txallowed = 1U; + int errorcode = 0; + __IO uint16_t tx_xfer_count; + __IO uint16_t rx_xfer_count; + + /* Init tickstart for timeout management*/ + tickstart = CurrentTicksGain() * 1000 / TICK_PER_SECOND; + + tmp = spi_init.SPI_Mode; + + if(!((tmp == SPI_Mode_Master) && (spi_init.SPI_Direction == SPI_Direction_2Lines_FullDuplex))){ + errorcode = 2; + goto error; + } + + if((p_txdata == NONE) || (p_rxdata == NONE) || (size == 0)){ + errorcode = 1; + goto error; + } + + tx_xfer_count = size; + rx_xfer_count = size; + + /* Check if the SPI is already enabled */ + if((spi_instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE) { + /* Enable SPI peripheral */ + spi_instance->CR1 |= SPI_CR1_SPE; + } + + /* Transmit and Receive data in 16 Bit mode */ + if(spi_init.SPI_DataSize == SPI_DataSize_16b) + { + if((spi_init.SPI_Mode == SPI_Mode_Slave) || (tx_xfer_count == 0x01U)) { + SPI_I2S_ReceiveData(spi_instance); + spi_instance->DR = *((uint16_t *)p_txdata); + + p_txdata += sizeof(uint16_t); + tx_xfer_count--; + } + while ((tx_xfer_count > 0U) || (rx_xfer_count > 0U)) + { + /* Check TXE flag */ + if(txallowed && (tx_xfer_count > 0U) && (SPI_I2S_GetFlagStatus(spi_instance, SPI_I2S_FLAG_TXE) == SET)) { + SPI_I2S_ReceiveData(spi_instance); + spi_instance->DR = *((uint16_t *)p_txdata); + p_txdata += sizeof(uint16_t); + tx_xfer_count--; + /* Next Data is a reception (Rx). Tx not allowed */ + txallowed = 0U; + } + + /* Check RXNE flag */ + if((rx_xfer_count > 0U) && (SPI_I2S_GetFlagStatus(spi_instance, SPI_I2S_FLAG_RXNE) == SET)) + { + *((uint16_t *)p_rxdata) = spi_instance->DR; + p_rxdata += sizeof(uint16_t); + rx_xfer_count--; + /* Next Data is a Transmission (Tx). Tx is allowed */ + txallowed = 1U; + } + if((Timeout != 0xFFFFFFFFU) && ((CurrentTicksGain() * 1000 / TICK_PER_SECOND-tickstart) >= Timeout)){ + errorcode = 3; + goto error; + } + } + } + /* Transmit and Receive data in 8 Bit mode */ + else + { + if((spi_init.SPI_Mode == SPI_Mode_Slave) || (tx_xfer_count == 0x01U)) + { + SPI_I2S_ReceiveData(spi_instance); + *((__IO uint8_t*)&spi_instance->DR) = (*p_txdata); + + p_txdata += sizeof(uint8_t); + tx_xfer_count--; + } + while((tx_xfer_count > 0U) || (rx_xfer_count > 0U)) + { + /* Wait for the send buffer to be empty, TXE event */ + if (txallowed && (tx_xfer_count > 0U) && (SPI_I2S_GetFlagStatus(spi_instance, SPI_I2S_FLAG_TXE) == SET)) + { + /* Write to the data register and write the data to be written into the transmit buffer */ + SPI_I2S_ReceiveData(spi_instance); + *((__IO uint8_t*)&spi_instance->DR) = (*p_txdata); + + p_txdata += sizeof(uint8_t); + tx_xfer_count--; + txallowed = 0U; + } + + if ((rx_xfer_count > 0U) && SPI_I2S_GetFlagStatus(spi_instance, SPI_I2S_FLAG_RXNE) == SET) + { + *(uint8_t *)p_rxdata = spi_instance->DR; + + p_rxdata += sizeof(uint8_t); + rx_xfer_count--; + txallowed = 1U; + } + if((Timeout != 0xFFFFFFFFU) && ((CurrentTicksGain() * 1000 / TICK_PER_SECOND-tickstart) >= Timeout)) { + errorcode = 3; + goto error; + } + } + } + + /* Wait until TXE flag */ + if(SpiWaitUntilTimeout(spi_init, spi_instance, SPI_FLAG_TXE, SET, Timeout, tickstart) != 0){ + errorcode = 3; + goto error; + } + + /* Check Busy flag */ + if(SpiWaitUntilTimeout(spi_init, spi_instance, SPI_FLAG_BSY, RESET, Timeout, tickstart) != 0){ + errorcode = 1; + goto error; + } + +error : + return errorcode; +} +/** + * This function SPI receive data + * + * @param spi_init SPI Init structure + * + * @param spi_instance SPI control handle + * + * @param p_data data buffer address + * + * @param size Amount of data + * + * @param Timeout waiting time + * + * @return if successful return EOK + */ +int SpiReceive(SPI_InitTypeDef spi_init, SPI_TypeDef *spi_instance, uint8_t *p_data, uint16_t size, uint32_t Timeout) +{ + uint32_t tickstart = 0U; + int errorcode = 0; + __IO uint16_t rx_xfer_count; + __IO uint32_t SPITimeout; + + if((spi_init.SPI_Mode == SPI_Mode_Master) && (spi_init.SPI_Direction == SPI_Direction_2Lines_FullDuplex)) { + /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */ + return SpiTransmitreceive(spi_init, spi_instance,p_data,p_data,size,Timeout); + } + + /* Init tickstart for timeout management*/ + tickstart = CurrentTicksGain() * 1000 / TICK_PER_SECOND; + + if((p_data == NONE ) || (size == 0)){ + errorcode = 1; + goto error; + } + + rx_xfer_count = size; + + /* Configure communication direction: 1Line */ + if(spi_init.SPI_Direction == SPI_Direction_1Line_Rx){ + spi_instance->CR1 &= (~SPI_CR1_BIDIOE); + } + + /* Check if the SPI is already enabled */ + if((spi_instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE){ + /* Enable SPI peripheral */ + spi_instance->CR1 |= SPI_CR1_SPE; + } + + /* Receive data in 8 Bit mode */ + if(spi_init.SPI_DataSize == SPI_DataSize_8b) + { + /* Transfer loop */ + while(rx_xfer_count > 0U) + { + SPITimeout = 0x1000; + + /* Wait for the send buffer to be empty, TXE event*/ + while (SPI_I2S_GetFlagStatus(spi_instance, SPI_I2S_FLAG_RXNE) == RESET) + { + if((SPITimeout--) == 0){ + KPrintf("spi time out\n"); + errorcode = 3; + goto error; + } + } + + *(uint8_t *)p_data = spi_instance->DR; + + p_data += sizeof(uint8_t); + rx_xfer_count--; + } + } + else + { + /* Transfer loop */ + while(rx_xfer_count > 0U) + { + SPITimeout = 0x1000; + /* Check the RXNE flag */ + while (SPI_I2S_GetFlagStatus(spi_instance, SPI_I2S_FLAG_RXNE) == RESET) + { + if((SPITimeout--) == 0) + { + KPrintf("spi time out\n"); + errorcode = 3; + goto error; + } + } + *((uint16_t*)p_data) = spi_instance->DR; + p_data += sizeof(uint16_t); + rx_xfer_count--; + } + } + + /* Check the end of the transaction */ + if((spi_init.SPI_Mode == SPI_Mode_Master)&&((spi_init.SPI_Direction == SPI_Direction_1Line_Rx)||(spi_init.SPI_Direction == SPI_Direction_2Lines_RxOnly))) + { + /* Disable SPI peripheral */ + spi_instance->CR1 &= (~SPI_CR1_SPE); + } + +error : + return errorcode; +} + +/** + * This function SPI write data + * + * @param spi_dev SPI device structure handle + * + * @param spi_datacfg SPI device information structure handle + * + * @return datacfg length + */ +static uint32 Stm32SpiWriteData(struct SpiHardwareDevice *spi_dev, struct SpiDataStandard *spi_datacfg) +{ + int state; + x_size_t message_length, already_send_length; + uint16 send_length; + const uint8 *WriteBuf; + + NULL_PARAM_CHECK(spi_dev); + NULL_PARAM_CHECK(spi_datacfg); + + struct Stm32Spi *StmSpi = CONTAINER_OF(spi_dev->haldev.owner_bus, struct Stm32Spi, spi_bus); + SPI_TypeDef *spi_instance = StmSpi->instance; + SPI_InitTypeDef *spi_init = &StmSpi->init; + struct Stm32HwSpiCs *cs = (struct Stm32HwSpiCs *)spi_dev->private_data; + + while(NONE != spi_datacfg) { + if(spi_datacfg->spi_chip_select) { + GPIO_WriteBit(cs->GPIOx, cs->GPIO_Pin, Bit_RESET); + } + + message_length = spi_datacfg->length; + WriteBuf = spi_datacfg->tx_buff; + while (message_length) { + if (message_length > 65535){ + send_length = 65535; + message_length = message_length - 65535; + } else { + send_length = message_length; + message_length = 0; + } + + /* calculate the start address */ + already_send_length = spi_datacfg->length - send_length - message_length; + WriteBuf = (uint8 *)spi_datacfg->tx_buff + already_send_length; + + /* start once data exchange in DMA mode */ + if (spi_datacfg->tx_buff) { + if (StmSpi->spi_dma_flag & SPI_USING_TX_DMA_FLAG) { + state = SpiTransmitDma(*spi_init, spi_instance, StmSpi->dma.dma_tx.init, StmSpi->dma.dma_tx.instance, (uint8_t *)WriteBuf, send_length); + } else { + state = SpiTransmit(*spi_init, spi_instance, (uint8_t *)WriteBuf, send_length, 1000); + } + } + + if (state != 0) { + KPrintf("spi write error : %d\n", state); + spi_datacfg->length = 0; + } + } + + if (spi_datacfg->spi_cs_release) { + GPIO_WriteBit(cs->GPIOx, cs->GPIO_Pin, Bit_SET); + } + + spi_datacfg = spi_datacfg->next; + } + + return EOK; +} + +/** + * This function SPI read data + * + * @param spi_dev SPI device structure handle + * + * @param spi_datacfg SPI device information structure handle + * + * @return datacfg length + */ +static uint32 Stm32SpiReadData(struct SpiHardwareDevice *spi_dev, struct SpiDataStandard *spi_datacfg) +{ + int state; + x_size_t message_length, already_send_length; + uint16 read_length, spi_read_length = 0; + const uint8 *ReadBuf; + + NULL_PARAM_CHECK(spi_dev); + NULL_PARAM_CHECK(spi_datacfg); + + struct Stm32Spi *StmSpi = CONTAINER_OF(spi_dev->haldev.owner_bus, struct Stm32Spi, spi_bus); + SPI_TypeDef *spi_instance = StmSpi->instance; + SPI_InitTypeDef *spi_init = &StmSpi->init; + struct Stm32HwSpiCs *cs = (struct Stm32HwSpiCs *)spi_dev->private_data; + + while (NONE != spi_datacfg) { + if (spi_datacfg->spi_chip_select) { + GPIO_WriteBit(cs->GPIOx, cs->GPIO_Pin, Bit_RESET); + } + + message_length = spi_datacfg->length; + ReadBuf = spi_datacfg->rx_buff; + while (message_length) { + if (message_length > 65535) { + read_length = 65535; + message_length = message_length - 65535; + } else { + read_length = message_length; + message_length = 0; + } + + /* calculate the start address */ + already_send_length = spi_datacfg->length - read_length - message_length; + ReadBuf = (uint8 *)spi_datacfg->rx_buff + already_send_length; + + /* start once data exchange in DMA mode */ + if (spi_datacfg->rx_buff) { + //memset((uint8_t *)ReadBuf, 0xff, read_length); + if (StmSpi->spi_dma_flag & SPI_USING_RX_DMA_FLAG) { + state = SpiReceiveDma(*spi_init, spi_instance, StmSpi->dma.dma_rx.init, StmSpi->dma.dma_rx.instance, StmSpi->dma.dma_tx.init, StmSpi->dma.dma_tx.instance, (uint8_t *)ReadBuf, read_length); + } else { + state = SpiReceive(*spi_init, spi_instance, (uint8_t *)ReadBuf, read_length, 1000); + } + } + + if (state != 0) { + KPrintf("spi read error : %d\n", state); + spi_datacfg->length = 0; + } + } + + if (spi_datacfg->spi_cs_release) { + GPIO_WriteBit(cs->GPIOx, cs->GPIO_Pin, Bit_SET); + } + + spi_read_length += spi_datacfg->length; + spi_datacfg = spi_datacfg->next; + } + + return spi_read_length; +} + +/** + * This function SPI driver initialization function + * + * @param spi_drv SPI driver structure handle + * + * @return if successful return EOK + */ +static uint32 SpiDrvInit(struct SpiDriver *spi_drv) +{ + NULL_PARAM_CHECK(spi_drv); + + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_drv->driver.private_data); + + struct Stm32Spi *StmSpi = CONTAINER_OF(spi_drv->driver.owner_bus, struct Stm32Spi, spi_bus); + + return Stm32SpiInit(StmSpi, dev_param->spi_master_param); +} + +/** + * This function SPI driver configuration param + * + * @param spi_drv SPI driver structure handle + * + * @param spi_param SPI master param structure handle + * + * @return if successful return EOK + */ +static uint32 SpiDrvConfigure(struct SpiDriver *spi_drv, struct SpiMasterParam *spi_param) +{ + NULL_PARAM_CHECK(spi_drv); + NULL_PARAM_CHECK(spi_param); + + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_drv->driver.private_data); + + dev_param->spi_master_param = spi_param; + dev_param->spi_master_param->spi_work_mode = dev_param->spi_master_param->spi_work_mode & SPI_MODE_MASK; + + return EOK; +} + +/*Configure the spi device param, make sure struct (configure_info->private_data) = (SpiMasterParam)*/ +static uint32 Stm32SpiDrvConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + struct SpiDriver *spi_drv = (struct SpiDriver *)drv; + struct SpiMasterParam *spi_param; + + switch (configure_info->configure_cmd) + { + case OPE_INT: + ret = SpiDrvInit(spi_drv); + break; + case OPE_CFG: + spi_param = (struct SpiMasterParam *)configure_info->private_data; + ret = SpiDrvConfigure(spi_drv, spi_param); + break; + default: + break; + } + + return ret; +} + +/*manage the spi device operations*/ +static const struct SpiDevDone spi_dev_done = +{ + .dev_open = NONE, + .dev_close = NONE, + .dev_write = Stm32SpiWriteData, + .dev_read = Stm32SpiReadData, +}; + +#if defined(BSP_USING_SPI1) +struct Stm32Spi spi1; +#if defined(BSP_SPI1_TX_USING_DMA) +void DMA2_Stream3_IRQHandler(int irq_num, void *arg) +{ + DmaTxDoneIsr(&spi1.spi_bus); +} +DECLARE_HW_IRQ(DMA2_Stream3_IRQn, DMA2_Stream3_IRQHandler, NONE); +#endif + +#if defined(BSP_SPI1_RX_USING_DMA) +void DMA2_Stream0_IRQHandler(int irq_num, void *arg) +{ + DmaRxDoneIsr(&spi1.spi_bus); +} +DECLARE_HW_IRQ(DMA2_Stream0_IRQn, DMA2_Stream0_IRQHandler, NONE); +#endif +#endif + +#if defined(BSP_USING_SPI2) +struct Stm32Spi spi2; +#if defined(BSP_SPI2_TX_USING_DMA) +void DMA1_Stream4_IRQHandler(int irq_num, void *arg) +{ + DmaTxDoneIsr(&spi2.spi_bus); +} +DECLARE_HW_IRQ(DMA1_Stream4_IRQn, DMA1_Stream4_IRQHandler, NONE); +#endif + +#if defined(BSP_SPI2_RX_USING_DMA) +void DMA1_Stream3_IRQHandler(int irq_num, void *arg) +{ + DmaTxDoneIsr(&spi2.spi_bus); +} +DECLARE_HW_IRQ(DMA1_Stream3_IRQn, DMA1_Stream3_IRQHandler, NONE); +#endif +#endif + +#if defined(BSP_USING_SPI3) +struct Stm32Spi spi3; +#if defined(BSP_SPI3_TX_USING_DMA) +void DMA1_Stream7_IRQHandler(int irq_num, void *arg) +{ + DmaTxDoneIsr(&spi3.spi_bus); +} +DECLARE_HW_IRQ(DMA1_Stream7_IRQn, DMA1_Stream7_IRQHandler, NONE); +#endif + +#if defined(BSP_SPI3_RX_USING_DMA) +/** + * This function DMA2 Stream2 Interrupt service function + * + * @return none + */ +void DMA1_Stream2_IRQHandler(int irq_num, void *arg) +{ + DmaRxDoneIsr(&spi3.spi_bus); +} +DECLARE_HW_IRQ(DMA1_Stream2_IRQn, DMA1_Stream2_IRQHandler, NONE); +#endif +#endif + +/** + * This function RCC clock configuration function + * + * @return none + */ +static void RCCConfiguration(void) +{ +#ifdef BSP_USING_SPI1 + RCC_AHB1PeriphClockCmd(SPI1_GPIO_RCC, ENABLE); + + RCC_APB2PeriphClockCmd(RCC_APBPeriph_SPI1, ENABLE); +#endif + +#ifdef BSP_USING_SPI2 + RCC_AHB1PeriphClockCmd(SPI2_GPIO_RCC | SPI2_GPIO_RCC_SCK, ENABLE); + + RCC_APB1PeriphClockCmd(RCC_APBPeriph_SPI2, ENABLE); +#endif + +#ifdef BSP_USING_SPI3 + RCC_AHB1PeriphClockCmd(SPI3_GPIO_RCC | SPI3_GPIO_RCC_NSS, ENABLE); + + RCC_APB2PeriphClockCmd(RCC_APBPeriph_SPI3, ENABLE); +#endif +} +/** + * This function GPIO Configuration function + * + * @return none + */ +static void GPIOConfiguration(void) +{ + GPIO_InitTypeDef gpio_initstructure; + + gpio_initstructure.GPIO_Mode = GPIO_Mode_AF; /* Reuse function */ + gpio_initstructure.GPIO_OType = GPIO_OType_PP; /* Multiplex push-pull*/ + gpio_initstructure.GPIO_PuPd = GPIO_PuPd_UP; /* pull up */ + gpio_initstructure.GPIO_Speed = GPIO_Speed_2MHz; /* Level reversal speed */ + +#ifdef BSP_USING_SPI1 + gpio_initstructure.GPIO_Pin = SPI1_GPIO_NSS | SPI1_GPIO_SCK | SPI1_GPIO_MISO | SPI1_GPIO_MOSI; + /* Connect alternate function */ + GPIO_PinAFConfig(SPI1_GPIO, SPI1_NSS_PIN_SOURCE, GPIO_AF_SPI1); + GPIO_PinAFConfig(SPI1_GPIO, SPI1_SCK_PIN_SOURCE, GPIO_AF_SPI1); + GPIO_PinAFConfig(SPI1_GPIO, SPI1_MISO_PIN_SOURCE, GPIO_AF_SPI1); + GPIO_PinAFConfig(SPI1_GPIO, SPI1_MOSI_PIN_SOURCE, GPIO_AF_SPI1); + + GPIO_Init(SPI1_GPIO, &gpio_initstructure); /*SPI pin initialization*/ +#endif + +#ifdef BSP_USING_SPI2 + gpio_initstructure.GPIO_Pin = SPI2_GPIO_SCK; + /* Connect alternate function */ + GPIO_PinAFConfig(SPI2_SCK, SPI2_SCK_PIN_SOURCE, GPIO_AF_SPI2); + + GPIO_Init(SPI2_SCK, &gpio_initstructure); + + gpio_initstructure.GPIO_Pin = SPI2_GPIO_NSS | SPI2_GPIO_MISO | SPI2_GPIO_MOSI; + /* Connect alternate function */ + GPIO_PinAFConfig(SPI2_GPIO, SPI2_NSS_PIN_SOURCE, GPIO_AF_SPI2); + GPIO_PinAFConfig(SPI2_GPIO, SPI2_MISO_PIN_SOURCE, GPIO_AF_SPI2); + GPIO_PinAFConfig(SPI2_GPIO, SPI2_MOSI_PIN_SOURCE, GPIO_AF_SPI2); + + GPIO_Init(SPI2_GPIO, &gpio_initstructure); +#endif + +#ifdef BSP_USING_SPI3 + gpio_initstructure.GPIO_Pin = SPI3_GPIO_NSS; + /* Connect alternate function */ + GPIO_PinAFConfig(SPI3_NSS, SPI3_NSS_PIN_SOURCE, GPIO_AF_SPI3); + + GPIO_Init(SPI3_NSS, &gpio_initstructure); + + gpio_initstructure.GPIO_Pin = SPI3_GPIO_SCK | SPI3_GPIO_MISO | SPI3_GPIO_MOSI; + GPIO_PinAFConfig(SPI3_GPIO, SPI3_SCK_PIN_SOURCE, GPIO_AF_SPI3); + GPIO_PinAFConfig(SPI3_GPIO, SPI3_MISO_PIN_SOURCE, GPIO_AF_SPI3); + GPIO_PinAFConfig(SPI3_GPIO, SPI3_MOSI_PIN_SOURCE, GPIO_AF_SPI3); + + GPIO_Init(SPI3_GPIO, &gpio_initstructure); +#endif +} + +/** + * This function Init the spi bus 、spi driver and attach to the bus + * + * @param spi_bus Spi bus info pointer + * + * @param spi_driver Spi driver info pointer + * + * @return EOK + */ +static int BoardSpiBusInit(struct Stm32Spi *stm32spi_bus, struct SpiDriver *spi_driver, char* drv_name) +{ + x_err_t ret = EOK; + + /*Init the spi bus */ + ret = SpiBusInit(&stm32spi_bus->spi_bus, stm32spi_bus->bus_name); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiBusInit error %d\n", ret); + return ERROR; + } + + /*Init the spi driver*/ + ret = SpiDriverInit(spi_driver, drv_name); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the spi driver to the spi bus*/ + ret = SpiDriverAttachToBus(drv_name, stm32spi_bus->bus_name); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + + +/** + * This function SPI bus initialization + * + * @return EOK + */ +static int Stm32HwSpiBusInit(void) +{ + x_err_t ret = EOK; + struct Stm32Spi *StmSpiBus; + + RCCConfiguration(); + GPIOConfiguration(); + +#ifdef BSP_USING_SPI1 + StmSpiBus = &spi1; + StmSpiBus->instance = SPI1; + StmSpiBus->bus_name = SPI_BUS_NAME_1; + StmSpiBus->spi_bus.private_data = &spi1; + DmaSpiConfig(&StmSpiBus->spi_bus, 0, NONE, NONE); + + static struct SpiDriver spi_driver_1; + memset(&spi_driver_1, 0, sizeof(struct SpiDriver)); + + spi_driver_1.configure = &(Stm32SpiDrvConfigure); + + ret = BoardSpiBusInit(StmSpiBus, &spi_driver_1, SPI_1_DRV_NAME); + if (EOK != ret) { + KPrintf("Board_Spi_Init spi_bus_init %s error ret %u\n", StmSpiBus->bus_name, ret); + return ERROR; + } +#endif + +#ifdef BSP_USING_SPI2 + StmSpiBus = &spi2; + StmSpiBus->instance = SPI2; + StmSpiBus->bus_name = SPI_BUS_NAME_2; + StmSpiBus->spi_bus.private_data = &spi2; + DmaSpiConfig(&StmSpiBus->spi_bus, 0, NONE, NONE); + + static struct SpiDriver spi_driver_2; + memset(&spi_driver_2, 0, sizeof(struct SpiDriver)); + + spi_driver_2.configure = &(Stm32SpiDrvConfigure); + + ret = BoardSpiBusInit(StmSpiBus, &spi_driver_2, SPI_2_DRV_NAME); + if (EOK != ret) { + KPrintf("Board_Spi_Init spi_bus_init %s error ret %u\n", StmSpiBus->bus_name, ret); + return ERROR; + } +#endif + +#ifdef BSP_USING_SPI3 + StmSpiBus = &spi3; + StmSpiBus->instance = SPI3; + StmSpiBus->bus_name = SPI_BUS_NAME_3; + StmSpiBus->spi_bus.private_data = &spi3; + DmaSpiConfig(&StmSpiBus->spi_bus, 0, NONE, NONE); + + static struct SpiDriver spi_driver_3; + memset(&spi_driver_3, 0, sizeof(struct SpiDriver)); + + spi_driver_3.configure = &(Stm32SpiDrvConfigure); + + ret = BoardSpiBusInit(StmSpiBus, &spi_driver_3, SPI_3_DRV_NAME); + if (EOK != ret) { + KPrintf("Board_Spi_Init spi_bus_init %s error ret %u\n", StmSpiBus->bus_name, ret); + return ERROR; + } +#endif + return EOK; +} + +/** + * This function Mount the spi device to the bus + * + * @param bus_name Bus Name + * + * @param device_name spi device name + * + * @param cs_gpiox GPIO pin configuration handle + * + * @param cs_gpio_pin GPIO number + * + * @return EOK + */ +x_err_t HwSpiDeviceAttach(const char *bus_name, const char *device_name, GPIO_TypeDef *cs_gpiox, uint16_t cs_gpio_pin) + +{ + NULL_PARAM_CHECK(bus_name); + NULL_PARAM_CHECK(device_name); + + x_err_t result; + struct SpiHardwareDevice *spi_device; + struct Stm32HwSpiCs *cs_pin_param; + static SpiDeviceParam spi_dev_param; + memset(&spi_dev_param, 0, sizeof(SpiDeviceParam)); + + /* initialize the cs pin && select the slave*/ + GPIO_InitTypeDef GPIO_Initure; + GPIO_Initure.GPIO_Pin = cs_gpio_pin; + GPIO_Initure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_Initure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(cs_gpiox, &GPIO_Initure); + GPIO_WriteBit(cs_gpiox, cs_gpio_pin, Bit_SET); + + /* attach the device to spi bus*/ + spi_device = (struct SpiHardwareDevice *)x_malloc(sizeof(struct SpiHardwareDevice)); + CHECK(spi_device); + memset(spi_device, 0, sizeof(struct SpiHardwareDevice)); + cs_pin_param = (struct Stm32HwSpiCs *)x_malloc(sizeof(struct Stm32HwSpiCs)); + CHECK(cs_pin_param); + memset(cs_pin_param, 0, sizeof(struct Stm32HwSpiCs)); + cs_pin_param->GPIOx = cs_gpiox; + cs_pin_param->GPIO_Pin = cs_gpio_pin; + + spi_device->spi_dev_done = &spi_dev_done; + spi_device->private_data = (void *)cs_pin_param; + + result = SpiDeviceRegister(spi_device, (void *)&spi_dev_param, device_name); + if (result != EOK) { + SYS_ERR("%s device %p register faild, %d\n", device_name, spi_device, result); + } + + result = SpiDeviceAttachToBus(device_name, bus_name); + if (result != EOK) { + SYS_ERR("%s attach to %s faild, %d\n", device_name, bus_name, result); + } + + CHECK(result == EOK); + + return result; +} + +/** + * This function Get DMA information + * + * @return none + */ +static void Stm32GetDmaInfo(void) +{ +#ifdef BSP_SPI1_RX_USING_DMA /*SPI1 uses DMA receive enable*/ + spi1.spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi1.dma.dma_rx.instance = DMA2_Stream0; + spi1.dma.dma_rx.dma_rcc = RCC_AHB1ENR_DMA2EN; + spi1.dma.dma_rx.channel = DMA_Channel_3; + spi1.dma.dma_rx.dma_irq = DMA2_Stream0_IRQn; +#endif +#ifdef BSP_SPI1_TX_USING_DMA /*SPI1 uses DMA send enable*/ + spi1.spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi1.dma.dma_tx.instance = DMA2_Stream3; + spi1.dma.dma_tx.dma_rcc = RCC_AHB1ENR_DMA2EN; + spi1.dma.dma_tx.channel = DMA_Channel_3; + spi1.dma.dma_tx.dma_irq = DMA2_Stream3_IRQn; +#endif + +#ifdef BSP_SPI2_RX_USING_DMA /*SPI2 uses DMA receive enable*/ + spi2.spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi2.dma.dma_rx.instance = DMA1_Stream3; /* DMA1 Data stream 3*/ + spi2.dma.dma_rx.dma_rcc = RCC_AHB1ENR_DMA1EN; + spi2.dma.dma_rx.channel = DMA_Channel_0; + spi2.dma.dma_rx.dma_irq = DMA1_Stream3_IRQn; +#endif +#ifdef BSP_SPI2_TX_USING_DMA /*SPI2 uses DMA send enable*/ + spi2.spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi2.dma.dma_tx.instance = DMA1_Stream4; /* DMA1 Data stream 4*/ + spi2.dma.dma_tx.dma_rcc = RCC_AHB1ENR_DMA1EN; + spi2.dma.dma_tx.channel = DMA_Channel_0; + spi2.dma.dma_tx.dma_irq = DMA1_Stream4_IRQn; /*Enable DMA interrupt line*/ +#endif + +#ifdef BSP_SPI3_RX_USING_DMA /*SPI3 uses DMA receive enable*/ + spi3.spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi3.dma.dma_rx.instance = DMA1_Stream2; /* DMA1 Data stream 2*/ + spi3.dma.dma_rx.dma_rcc = RCC_AHB1ENR_DMA1EN; + spi3.dma.dma_rx.channel = DMA_Channel_0; + spi3.dma.dma_rx.dma_irq = DMA1_Stream2_IRQn; /*Enable DMA interrupt line*/ +#endif +#ifdef BSP_SPI3_TX_USING_DMA /*SPI3 uses DMA send enable*/ + spi3.spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi3.dma.dma_tx.instance = DMA1_Stream7; /* DMA1 Data stream 7*/ + spi3.dma.dma_tx.dma_rcc = RCC_AHB1ENR_DMA1EN; + spi3.dma.dma_tx.channel = DMA_Channel_0; + spi3.dma.dma_tx.dma_irq = DMA1_Stream7_IRQn; /*Enable DMA interrupt line*/ +#endif +} + +/** + * This function hardware spi initialization + * + * @return EOK + */ +int Stm32HwSpiInit(void) +{ + Stm32GetDmaInfo(); + return Stm32HwSpiBusInit(); +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/flexspi_nor_flash_ops.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/flexspi_nor_flash_ops.c new file mode 100755 index 000000000..6786d4049 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/flexspi_nor_flash_ops.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_flexspi.h" +#include "app.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + *****************************************************************************/ +extern flexspi_device_config_t deviceconfig; +extern const uint32_t customLUT[CUSTOM_LUT_LENGTH]; +/******************************************************************************* + * Code + ******************************************************************************/ +status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr) +{ + flexspi_transfer_t flashXfer; + status_t status; + + /* Write enable */ + flashXfer.deviceAddress = baseAddr; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Command; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE; + + status = FLEXSPI_TransferBlocking(base, &flashXfer); + + return status; +} + +status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) +{ + /* Wait status ready. */ + bool isBusy; + uint32_t readValue; + status_t status; + flexspi_transfer_t flashXfer; + + flashXfer.deviceAddress = 0; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Read; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READSTATUSREG; + flashXfer.data = &readValue; + flashXfer.dataSize = 1; + + do + { + status = FLEXSPI_TransferBlocking(base, &flashXfer); + + if (status != kStatus_Success) + { + return status; + } + if (FLASH_BUSY_STATUS_POL) + { + if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET)) + { + isBusy = true; + } + else + { + isBusy = false; + } + } + else + { + if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET)) + { + isBusy = false; + } + else + { + isBusy = true; + } + } + + } while (isBusy); + + return status; +} + +status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) +{ + flexspi_transfer_t flashXfer; + status_t status; + uint32_t writeValue = FLASH_QUAD_ENABLE; + + /* Write enable */ + status = flexspi_nor_write_enable(base, 0); + + if (status != kStatus_Success) + { + return status; + } + + /* Enable quad mode. */ + flashXfer.deviceAddress = 0; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Write; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG; + flashXfer.data = &writeValue; + flashXfer.dataSize = 1; + + status = FLEXSPI_TransferBlocking(base, &flashXfer); + if (status != kStatus_Success) + { + return status; + } + + status = flexspi_nor_wait_bus_busy(base); + + /* Do software reset. */ + FLEXSPI_SoftwareReset(base); + + return status; +} + +status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) +{ + status_t status; + flexspi_transfer_t flashXfer; + + /* Write enable */ + flashXfer.deviceAddress = address; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Command; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE; + + status = FLEXSPI_TransferBlocking(base, &flashXfer); + + if (status != kStatus_Success) + { + return status; + } + + flashXfer.deviceAddress = address; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Command; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASESECTOR; + status = FLEXSPI_TransferBlocking(base, &flashXfer); + + if (status != kStatus_Success) + { + return status; + } + + status = flexspi_nor_wait_bus_busy(base); + + /* Do software reset. */ + FLEXSPI_SoftwareReset(base); + + return status; +} + +status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src) +{ + status_t status; + flexspi_transfer_t flashXfer; + + /* Write enable */ + status = flexspi_nor_write_enable(base, dstAddr); + + if (status != kStatus_Success) + { + return status; + } + + /* Prepare page program command */ + flashXfer.deviceAddress = dstAddr; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Write; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD; + flashXfer.data = (uint32_t *)src; + flashXfer.dataSize = FLASH_PAGE_SIZE; + status = FLEXSPI_TransferBlocking(base, &flashXfer); + + if (status != kStatus_Success) + { + return status; + } + + status = flexspi_nor_wait_bus_busy(base); + + /* Do software reset. */ + FLEXSPI_SoftwareReset(base); + + return status; +} + +status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId) +{ + uint32_t temp; + flexspi_transfer_t flashXfer; + flashXfer.deviceAddress = 0; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Read; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READID; + flashXfer.data = &temp; + flashXfer.dataSize = 1; + + status_t status = FLEXSPI_TransferBlocking(base, &flashXfer); + + *vendorId = temp; + + /* Do software reset. */ + FLEXSPI_SoftwareReset(base); + + return status; +} + +status_t flexspi_nor_erase_chip(FLEXSPI_Type *base) +{ + status_t status; + flexspi_transfer_t flashXfer; + + /* Write enable */ + status = flexspi_nor_write_enable(base, 0); + + if (status != kStatus_Success) + { + return status; + } + + flashXfer.deviceAddress = 0; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Command; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASECHIP; + + status = FLEXSPI_TransferBlocking(base, &flashXfer); + + if (status != kStatus_Success) + { + return status; + } + + status = flexspi_nor_wait_bus_busy(base); + + return status; +} + +void flexspi_nor_flash_init(FLEXSPI_Type *base) +{ + flexspi_config_t config; + + flexspi_clock_init(); + + /*Get FLEXSPI default settings and configure the flexspi. */ + FLEXSPI_GetDefaultConfig(&config); + + /*Set AHB buffer size for reading data through AHB bus. */ + config.ahbConfig.enableAHBPrefetch = true; + config.ahbConfig.enableAHBBufferable = true; + config.ahbConfig.enableReadAddressOpt = true; + config.ahbConfig.enableAHBCachable = true; + config.rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackFromDqsPad; + FLEXSPI_Init(base, &config); + + /* Configure flash settings according to serial flash feature. */ + FLEXSPI_SetFlashConfig(base, &deviceconfig, kFLEXSPI_PortA1); + + /* Update LUT table. */ + FLEXSPI_UpdateLUT(base, 0, customLUT, CUSTOM_LUT_LENGTH); + + /* Do software reset. */ + FLEXSPI_SoftwareReset(base); +} diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/flexspi_nor_polling_transfer.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/flexspi_nor_polling_transfer.c new file mode 100755 index 000000000..c67837b4a --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/flexspi_nor_polling_transfer.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_flexspi.h" +#include "app.h" +#include "fsl_debug_console.h" +#include "fsl_cache.h" + +#include "pin_mux.h" +#include "board.h" +#include "clock_config.h" +#include "fsl_common.h" + +#include + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +static uint8_t s_nor_program_buffer[256]; +static uint8_t s_nor_read_buffer[256]; + +extern status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address); +extern status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src); +extern status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId); +extern status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base); +extern status_t flexspi_nor_erase_chip(FLEXSPI_Type *base); +extern void flexspi_nor_flash_init(FLEXSPI_Type *base); +/******************************************************************************* + * Code + ******************************************************************************/ +flexspi_device_config_t deviceconfig = { + .flexspiRootClk = 120000000, + .flashSize = FLASH_SIZE, + .CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle, + .CSInterval = 2, + .CSHoldTime = 3, + .CSSetupTime = 3, + .dataValidTime = 0, + .columnspace = 0, + .enableWordAddress = 0, + .AWRSeqIndex = 0, + .AWRSeqNumber = 0, + .ARDSeqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD, + .ARDSeqNumber = 1, + .AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle, + .AHBWriteWaitInterval = 0, +}; + +const uint32_t customLUT[CUSTOM_LUT_LENGTH] = { + /* Normal read mode -SDR */ + [4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + [4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + + /* Fast read mode - SDR */ + [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST + 1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), + + /* Fast read quad mode - SDR */ + [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18), + [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04), + + /* Read extend parameters */ + [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), + + /* Write Enable */ + [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + + /* Erase Sector */ + [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + + /* Page Program - single mode */ + [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + + /* Page Program - quad mode */ + [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD + 1] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + + /* Read ID */ + [4 * NOR_CMD_LUT_SEQ_IDX_READID] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), + + /* Enable Quad mode */ + [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x01, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04), + + /* Enter QPI mode */ + [4 * NOR_CMD_LUT_SEQ_IDX_ENTERQPI] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + + /* Exit QPI mode */ + [4 * NOR_CMD_LUT_SEQ_IDX_EXITQPI] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + + /* Read status register */ + [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), + + /* Erase whole chip */ + [4 * NOR_CMD_LUT_SEQ_IDX_ERASECHIP] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC7, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), +}; + + +int test_nor_flash(void) +{ + uint32_t i = 0; + status_t status; + uint8_t vendorID = 0; + +// BOARD_ConfigMPU(); +// BOARD_InitPins(); +// BOARD_BootClockRUN(); +// BOARD_InitDebugConsole(); + BOARD_InitSPIPins(); +// SCB_DisableDCache(); +// spi_trace(); + flexspi_nor_flash_init(EXAMPLE_FLEXSPI); + + spi_print("\r\nFLEXSPI example started!\r\n"); + + /* Get vendor ID. */ + status = flexspi_nor_get_vendor_id(EXAMPLE_FLEXSPI, &vendorID); + if (status != kStatus_Success) + { + spi_print("flexspi status %d\r\n", status); + return status; + } + spi_print("Vendor ID: 0x%x\r\n", vendorID); + + return 0; +#if !(defined(XIP_EXTERNAL_FLASH)) + /* Erase whole chip . */ + spi_print("Erasing whole chip over FlexSPI...\r\n"); + + status = flexspi_nor_erase_chip(EXAMPLE_FLEXSPI); + if (status != kStatus_Success) + { + return status; + } + spi_print("Erase finished !\r\n"); + +#endif + + /* Enter quad mode. */ + status = flexspi_nor_enable_quad_mode(EXAMPLE_FLEXSPI); + if (status != kStatus_Success) + { + return status; + } + + /* Erase sectors. */ + spi_print("Erasing Serial NOR over FlexSPI...\r\n"); + status = flexspi_nor_flash_erase_sector(EXAMPLE_FLEXSPI, EXAMPLE_SECTOR * SECTOR_SIZE); + if (status != kStatus_Success) + { + spi_print("Erase sector failure !\r\n"); + return -1; + } + + memset(s_nor_program_buffer, 0xFFU, sizeof(s_nor_program_buffer)); + memcpy(s_nor_read_buffer, (void *)(EXAMPLE_FLEXSPI_AMBA_BASE + EXAMPLE_SECTOR * SECTOR_SIZE), + sizeof(s_nor_read_buffer)); + + if (memcmp(s_nor_program_buffer, s_nor_read_buffer, sizeof(s_nor_program_buffer))) + { + spi_print("Erase data - read out data value incorrect !\r\n "); + return -1; + } + else + { + spi_print("Erase data - successfully. \r\n"); + } + + for (i = 0; i < 0xFFU; i++) + { + s_nor_program_buffer[i] = i; + } + + status = + flexspi_nor_flash_page_program(EXAMPLE_FLEXSPI, EXAMPLE_SECTOR * SECTOR_SIZE, (void *)s_nor_program_buffer); + if (status != kStatus_Success) + { + spi_print("Page program failure !\r\n"); + return -1; + } + + DCACHE_CleanInvalidateByRange(EXAMPLE_FLEXSPI_AMBA_BASE + EXAMPLE_SECTOR * SECTOR_SIZE, FLASH_PAGE_SIZE); + + memcpy(s_nor_read_buffer, (void *)(EXAMPLE_FLEXSPI_AMBA_BASE + EXAMPLE_SECTOR * SECTOR_SIZE), + sizeof(s_nor_read_buffer)); + + if (memcmp(s_nor_read_buffer, s_nor_program_buffer, sizeof(s_nor_program_buffer)) != 0) + { + spi_print("Program data - read out data value incorrect !\r\n "); + return -1; + } + else + { + spi_print("Program data - successfully. \r\n"); + } + + while (1) + { + } +} + +SHELL_EXPORT_CMD (SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0), + nor, test_nor_flash, Nor flash test ); + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_flexspi.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_flexspi.c new file mode 100755 index 000000000..c10b16f2e --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_flexspi.c @@ -0,0 +1,1063 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_flexspi.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.flexspi" +#endif + +/******************************************************************************* + * Definitations + ******************************************************************************/ + +#define FREQ_1MHz (1000000UL) +#define FLEXSPI_DLLCR_DEFAULT (0x100UL) +#define FLEXSPI_LUT_KEY_VAL (0x5AF05AF0ul) + +enum +{ + kFLEXSPI_DelayCellUnitMin = 75, /* 75ps. */ + kFLEXSPI_DelayCellUnitMax = 225, /* 225ps. */ +}; + +enum +{ + kFLEXSPI_FlashASampleClockSlaveDelayLocked = + FLEXSPI_STS2_ASLVLOCK_MASK, /* Flash A sample clock slave delay line locked. */ + kFLEXSPI_FlashASampleClockRefDelayLocked = + FLEXSPI_STS2_AREFLOCK_MASK, /* Flash A sample clock reference delay line locked. */ + kFLEXSPI_FlashBSampleClockSlaveDelayLocked = + FLEXSPI_STS2_BSLVLOCK_MASK, /* Flash B sample clock slave delay line locked. */ + kFLEXSPI_FlashBSampleClockRefDelayLocked = + FLEXSPI_STS2_BREFLOCK_MASK, /* Flash B sample clock reference delay line locked. */ +}; + +/*! @brief Common sets of flags used by the driver. */ +enum _flexspi_flag_constants +{ + /*! IRQ sources enabled by the non-blocking transactional API. */ + kIrqFlags = kFLEXSPI_IpTxFifoWatermarkEmpltyFlag | kFLEXSPI_IpRxFifoWatermarkAvailableFlag | + kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag | + kFLEXSPI_IpCommandGrantTimeoutFlag | kFLEXSPI_IpCommandExcutionDoneFlag, + + /*! Errors to check for. */ + kErrorFlags = kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag | + kFLEXSPI_IpCommandGrantTimeoutFlag, +}; + +enum _flexspi_transfer_state +{ + kFLEXSPI_Idle = 0x0U, /*!< Transfer is done. */ + kFLEXSPI_BusyWrite = 0x1U, /*!< FLEXSPI is busy write transfer. */ + kFLEXSPI_BusyRead = 0x2U, /*!< FLEXSPI is busy write transfer. */ +}; + +/*! @brief Typedef for interrupt handler. */ +typedef void (*flexspi_isr_t)(FLEXSPI_Type *base, void *flexspiHandle); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Get the instance number for FLEXSPI. + * + * @param base FLEXSPI base pointer. + */ +uint32_t FLEXSPI_GetInstance(FLEXSPI_Type *base); + +/*! + * @brief Configure flash A/B sample clock DLL. + * + * @param base FLEXSPI base pointer. + * @param config Flash configuration parameters. + */ +static uint32_t FLEXSPI_ConfigureDll(FLEXSPI_Type *base, flexspi_device_config_t *config); + +/*! + * @brief Check and clear IP command execution errors. + * + * @param base FLEXSPI base pointer. + * @param status interrupt status. + */ +status_t FLEXSPI_CheckAndClearError(FLEXSPI_Type *base, uint32_t status); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Pointers to flexspi bases for each instance. */ +static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS; + +/*! @brief Pointers to flexspi IRQ number for each instance. */ +static const IRQn_Type s_flexspiIrqs[] = FLEXSPI_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/* Clock name array */ +static const clock_ip_name_t s_flexspiClock[] = FLEXSPI_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ +/*! @brief Pointers to flexspi handles for each instance. */ +static void *s_flexspiHandle[ARRAY_SIZE(s_flexspiBases)]; +#endif + +#if defined(FSL_FEATURE_FLEXSPI_HAS_RESET) && FSL_FEATURE_FLEXSPI_HAS_RESET +/*! @brief Pointers to FLEXSPI resets for each instance. */ +static const reset_ip_name_t s_flexspiResets[] = FLEXSPI_RSTS; +#endif +/******************************************************************************* + * Code + ******************************************************************************/ + +uint32_t FLEXSPI_GetInstance(FLEXSPI_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_flexspiBases); instance++) + { + if (s_flexspiBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_flexspiBases)); + + return instance; +} + +static uint32_t FLEXSPI_ConfigureDll(FLEXSPI_Type *base, flexspi_device_config_t *config) +{ + bool isUnifiedConfig = true; + uint32_t flexspiDllValue; + uint32_t dllValue; + uint32_t temp; + + uint8_t rxSampleClock = (base->MCR0 & FLEXSPI_MCR0_RXCLKSRC_MASK) >> FLEXSPI_MCR0_RXCLKSRC_SHIFT; + switch (rxSampleClock) + { + case kFLEXSPI_ReadSampleClkLoopbackInternally: + case kFLEXSPI_ReadSampleClkLoopbackFromDqsPad: + case kFLEXSPI_ReadSampleClkLoopbackFromSckPad: + isUnifiedConfig = true; + break; + case kFLEXSPI_ReadSampleClkExternalInputFromDqsPad: + if (config->isSck2Enabled) + { + isUnifiedConfig = true; + } + else + { + isUnifiedConfig = false; + } + break; + default: + break; + } + + if (isUnifiedConfig) + { + flexspiDllValue = FLEXSPI_DLLCR_DEFAULT; /* 1 fixed delay cells in DLL delay chain) */ + } + else + { + if (config->flexspiRootClk >= 100 * FREQ_1MHz) + { + /* DLLEN = 1, SLVDLYTARGET = 0xF, */ + flexspiDllValue = FLEXSPI_DLLCR_DLLEN(1) | FLEXSPI_DLLCR_SLVDLYTARGET(0x0F); + } + else + { + temp = config->dataValidTime * 1000; /* Convert data valid time in ns to ps. */ + dllValue = temp / kFLEXSPI_DelayCellUnitMin; + if (dllValue * kFLEXSPI_DelayCellUnitMin < temp) + { + dllValue++; + } + flexspiDllValue = FLEXSPI_DLLCR_OVRDEN(1) | FLEXSPI_DLLCR_OVRDVAL(dllValue); + } + } + return flexspiDllValue; +} + +status_t FLEXSPI_CheckAndClearError(FLEXSPI_Type *base, uint32_t status) +{ + status_t result = kStatus_Success; + + /* Check for error. */ + status &= kErrorFlags; + if (status) + { + /* Select the correct error code.. */ + if (status & kFLEXSPI_SequenceExecutionTimeoutFlag) + { + result = kStatus_FLEXSPI_SequenceExecutionTimeout; + } + else if (status & kFLEXSPI_IpCommandSequenceErrorFlag) + { + result = kStatus_FLEXSPI_IpCommandSequenceError; + } + else if (status & kFLEXSPI_IpCommandGrantTimeoutFlag) + { + result = kStatus_FLEXSPI_IpCommandGrantTimeout; + } + else + { + assert(false); + } + + /* Clear the flags. */ + FLEXSPI_ClearInterruptStatusFlags(base, status); + + /* Reset fifos. These flags clear automatically. */ + base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK; + base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK; + } + + return result; +} + +/*! + * brief Initializes the FLEXSPI module and internal state. + * + * This function enables the clock for FLEXSPI and also configures the FLEXSPI with the + * input configure parameters. Users should call this function before any FLEXSPI operations. + * + * param base FLEXSPI peripheral base address. + * param config FLEXSPI configure structure. + */ +void FLEXSPI_Init(FLEXSPI_Type *base, const flexspi_config_t *config) +{ + uint32_t configValue = 0; + uint8_t i = 0; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Enable the flexspi clock */ + CLOCK_EnableClock(s_flexspiClock[FLEXSPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +#if defined(FSL_FEATURE_FLEXSPI_HAS_RESET) && FSL_FEATURE_FLEXSPI_HAS_RESET + /* Reset the FLEXSPI module */ + RESET_PeripheralReset(s_flexspiResets[FLEXSPI_GetInstance(base)]); +#endif + + /* Reset peripheral before configuring it. */ + base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK; + FLEXSPI_SoftwareReset(base); + + /* Configure MCR0 configuration items. */ + configValue = FLEXSPI_MCR0_RXCLKSRC(config->rxSampleClock) | FLEXSPI_MCR0_DOZEEN(config->enableDoze) | + FLEXSPI_MCR0_IPGRANTWAIT(config->ipGrantTimeoutCycle) | + FLEXSPI_MCR0_AHBGRANTWAIT(config->ahbConfig.ahbGrantTimeoutCycle) | + FLEXSPI_MCR0_SCKFREERUNEN(config->enableSckFreeRunning) | + FLEXSPI_MCR0_HSEN(config->enableHalfSpeedAccess) | + FLEXSPI_MCR0_COMBINATIONEN(config->enableCombination) | + FLEXSPI_MCR0_ATDFEN(config->ahbConfig.enableAHBWriteIpTxFifo) | + FLEXSPI_MCR0_ARDFEN(config->ahbConfig.enableAHBWriteIpRxFifo) | FLEXSPI_MCR0_MDIS_MASK; + base->MCR0 = configValue; + + /* Configure MCR1 configurations. */ + configValue = + FLEXSPI_MCR1_SEQWAIT(config->seqTimeoutCycle) | FLEXSPI_MCR1_AHBBUSWAIT(config->ahbConfig.ahbBusTimeoutCycle); + base->MCR1 = configValue; + + /* Configure MCR2 configurations. */ + configValue = base->MCR2; + configValue &= ~(FLEXSPI_MCR2_RESUMEWAIT_MASK | FLEXSPI_MCR2_SCKBDIFFOPT_MASK | FLEXSPI_MCR2_SAMEDEVICEEN_MASK | + FLEXSPI_MCR2_CLRAHBBUFOPT_MASK); + configValue |= FLEXSPI_MCR2_RESUMEWAIT(config->ahbConfig.resumeWaitCycle) | + FLEXSPI_MCR2_SCKBDIFFOPT(config->enableSckBDiffOpt) | + FLEXSPI_MCR2_SAMEDEVICEEN(config->enableSameConfigForAll) | + FLEXSPI_MCR2_CLRAHBBUFOPT(config->ahbConfig.enableClearAHBBufferOpt); + + base->MCR2 = configValue; + + /* Configure AHB control items. */ + configValue = base->AHBCR; + configValue &= ~(FLEXSPI_AHBCR_READADDROPT_MASK | FLEXSPI_AHBCR_PREFETCHEN_MASK | FLEXSPI_AHBCR_BUFFERABLEEN_MASK | + FLEXSPI_AHBCR_CACHABLEEN_MASK); + configValue |= FLEXSPI_AHBCR_READADDROPT(config->ahbConfig.enableReadAddressOpt) | + FLEXSPI_AHBCR_PREFETCHEN(config->ahbConfig.enableAHBPrefetch) | + FLEXSPI_AHBCR_BUFFERABLEEN(config->ahbConfig.enableAHBBufferable) | + FLEXSPI_AHBCR_CACHABLEEN(config->ahbConfig.enableAHBCachable); + base->AHBCR = configValue; + + /* Configure AHB rx buffers. */ + for (i = 0; i < FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT; i++) + { + configValue = base->AHBRXBUFCR0[i]; + + configValue &= ~(FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK | + FLEXSPI_AHBRXBUFCR0_MSTRID_MASK | FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK); + configValue |= FLEXSPI_AHBRXBUFCR0_PREFETCHEN(config->ahbConfig.buffer[i].enablePrefetch) | + FLEXSPI_AHBRXBUFCR0_PRIORITY(config->ahbConfig.buffer[i].priority) | + FLEXSPI_AHBRXBUFCR0_MSTRID(config->ahbConfig.buffer[i].masterIndex) | + FLEXSPI_AHBRXBUFCR0_BUFSZ(config->ahbConfig.buffer[i].bufferSize / 8); + base->AHBRXBUFCR0[i] = configValue; + } + + /* Configure IP Fifo watermarks. */ + base->IPRXFCR &= ~FLEXSPI_IPRXFCR_RXWMRK_MASK; + base->IPRXFCR |= FLEXSPI_IPRXFCR_RXWMRK(config->rxWatermark / 8 - 1); + base->IPTXFCR &= ~FLEXSPI_IPTXFCR_TXWMRK_MASK; + base->IPTXFCR |= FLEXSPI_IPTXFCR_TXWMRK(config->txWatermark / 8 - 1); + + /* Reset flash size on all ports */ + for (i = 0; i < kFLEXSPI_PortCount; i++) + { + base->FLSHCR0[i] = 0; + } +} + +/*! + * brief Gets default settings for FLEXSPI. + * + * param config FLEXSPI configuration structure. + */ +void FLEXSPI_GetDefaultConfig(flexspi_config_t *config) +{ + /* Initializes the configure structure to zero. */ + memset(config, 0, sizeof(*config)); + + config->rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackInternally; + config->enableSckFreeRunning = false; + config->enableCombination = false; + config->enableDoze = true; + config->enableHalfSpeedAccess = false; + config->enableSckBDiffOpt = false; + config->enableSameConfigForAll = false; + config->seqTimeoutCycle = 0xFFFFU; + config->ipGrantTimeoutCycle = 0xFFU; + config->txWatermark = 8; + config->rxWatermark = 8; + config->ahbConfig.enableAHBWriteIpTxFifo = false; + config->ahbConfig.enableAHBWriteIpRxFifo = false; + config->ahbConfig.ahbGrantTimeoutCycle = 0xFFU; + config->ahbConfig.ahbBusTimeoutCycle = 0xFFFFU; + config->ahbConfig.resumeWaitCycle = 0x20U; + memset(config->ahbConfig.buffer, 0, sizeof(config->ahbConfig.buffer)); + for (uint8_t i = 0; i < FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT; i++) + { + config->ahbConfig.buffer[i].enablePrefetch = true; /* Default enable AHB prefetch. */ + config->ahbConfig.buffer[i].bufferSize = 256; /* Default buffer size 256 bytes*/ + } + config->ahbConfig.enableClearAHBBufferOpt = false; + config->ahbConfig.enableReadAddressOpt = false; + config->ahbConfig.enableAHBPrefetch = false; + config->ahbConfig.enableAHBBufferable = false; + config->ahbConfig.enableAHBCachable = false; +} + +/*! + * brief Deinitializes the FLEXSPI module. + * + * Clears the FLEXSPI state and FLEXSPI module registers. + * param base FLEXSPI peripheral base address. + */ +void FLEXSPI_Deinit(FLEXSPI_Type *base) +{ + /* Reset peripheral. */ + FLEXSPI_SoftwareReset(base); +} + +/*! + * brief Configures the connected device parameter. + * + * This function configures the connected device relevant parameters, such as the size, command, and so on. + * The flash configuration value cannot have a default value. The user needs to configure it according to the + * connected device. + * + * param base FLEXSPI peripheral base address. + * param config Flash configuration parameters. + * param port FLEXSPI Operation port. + */ +void FLEXSPI_SetFlashConfig(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port) +{ + uint32_t configValue = 0; + uint32_t statusValue = 0; + uint8_t index = port >> 1; /* PortA with index 0, PortB with index 1. */ + + /* Wait for bus idle before change flash configuration. */ + while (!FLEXSPI_GetBusIdleStatus(base)) + { + } + + /* Configure flash size. */ + base->FLSHCR0[port] = config->flashSize; + + /* Configure flash parameters. */ + base->FLSHCR1[port] = FLEXSPI_FLSHCR1_CSINTERVAL(config->CSInterval) | + FLEXSPI_FLSHCR1_CSINTERVALUNIT(config->CSIntervalUnit) | + FLEXSPI_FLSHCR1_TCSH(config->CSHoldTime) | FLEXSPI_FLSHCR1_TCSS(config->CSSetupTime) | + FLEXSPI_FLSHCR1_CAS(config->columnspace) | FLEXSPI_FLSHCR1_WA(config->enableWordAddress); + + /* Configure AHB operation items. */ + configValue = base->FLSHCR2[port]; + + configValue &= ~(FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK | FLEXSPI_FLSHCR2_AWRWAIT_MASK | FLEXSPI_FLSHCR2_AWRSEQNUM_MASK | + FLEXSPI_FLSHCR2_AWRSEQID_MASK | FLEXSPI_FLSHCR2_ARDSEQNUM_MASK | FLEXSPI_FLSHCR2_AWRSEQID_MASK); + + configValue |= + FLEXSPI_FLSHCR2_AWRWAITUNIT(config->AHBWriteWaitUnit) | FLEXSPI_FLSHCR2_AWRWAIT(config->AHBWriteWaitInterval); + + if (config->AWRSeqNumber > 0U) + { + configValue |= + FLEXSPI_FLSHCR2_AWRSEQID(config->AWRSeqIndex) | FLEXSPI_FLSHCR2_AWRSEQNUM(config->AWRSeqNumber - 1U); + } + + if (config->ARDSeqNumber > 0U) + { + configValue |= + FLEXSPI_FLSHCR2_ARDSEQID(config->ARDSeqIndex) | FLEXSPI_FLSHCR2_ARDSEQNUM(config->ARDSeqNumber - 1U); + } + + base->FLSHCR2[port] = configValue; + + /* Configure DLL. */ + configValue = FLEXSPI_ConfigureDll(base, config); + base->DLLCR[index] = configValue; + + /* Configure write mask. */ + if (config->enableWriteMask) + { + base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMOPT1_MASK; + } + else + { + base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMOPT1_MASK; + } + + if (index == 0) /*PortA*/ + { + base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENA_MASK; + base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENA(config->enableWriteMask); + } + else + { + base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENB_MASK; + base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENB(config->enableWriteMask); + } + + /* Exit stop mode. */ + base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK; + + /* According to ERR011377, need to delay at least 100 NOPs to ensure the DLL is locked. */ + statusValue = (index == 0) ? + (kFLEXSPI_FlashASampleClockSlaveDelayLocked | kFLEXSPI_FlashASampleClockRefDelayLocked) : + (kFLEXSPI_FlashBSampleClockSlaveDelayLocked | kFLEXSPI_FlashBSampleClockRefDelayLocked); + + if (configValue & FLEXSPI_DLLCR_DLLEN_MASK) + { + /* Wait slave delay line locked and slave reference delay line locked. */ + while ((base->STS2 & statusValue) != statusValue) + { + } + + /* Wait at least 100 NOPs*/ + for (uint8_t delay = 100; delay > 0; delay--) + { + __NOP(); + } + } +} + +/*! brief Updates the LUT table. + * + * param base FLEXSPI peripheral base address. + * param index From which index start to update. It could be any index of the LUT table, which + * also allows user to update command content inside a command. Each command consists of up to + * 8 instructions and occupy 4*32-bit memory. + * param cmd Command sequence array. + * param count Number of sequences. + */ +void FLEXSPI_UpdateLUT(FLEXSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count) +{ + assert(index < 64U); + + uint8_t i = 0; + volatile uint32_t *lutBase; + + /* Wait for bus idle before change flash configuration. */ + while (!FLEXSPI_GetBusIdleStatus(base)) + { + } + + /* Unlock LUT for update. */ + base->LUTKEY = FLEXSPI_LUT_KEY_VAL; + base->LUTCR = 0x02; + + lutBase = &base->LUT[index]; + for (i = 0; i < count; i++) + { + *lutBase++ = *cmd++; + } + + /* Lock LUT. */ + base->LUTKEY = FLEXSPI_LUT_KEY_VAL; + base->LUTCR = 0x01; +} + +/*! brief Update read sample clock source + * + * param base FLEXSPI peripheral base address. + * param clockSource clockSource of type #flexspi_read_sample_clock_t + */ +void FLEXSPI_UpdateRxSampleClock(FLEXSPI_Type *base, flexspi_read_sample_clock_t clockSource) +{ + uint32_t mcr0Val; + + /* Wait for bus idle before change flash configuration. */ + while (!FLEXSPI_GetBusIdleStatus(base)) + { + } + + mcr0Val = base->MCR0; + mcr0Val &= ~FLEXSPI_MCR0_RXCLKSRC_MASK; + mcr0Val |= FLEXSPI_MCR0_RXCLKSRC(clockSource); + base->MCR0 = mcr0Val; + + /* Reset peripheral. */ + FLEXSPI_SoftwareReset(base); +} + +/*! + * brief Sends a buffer of data bytes using blocking method. + * note This function blocks via polling until all bytes have been sent. + * param base FLEXSPI peripheral base address + * param buffer The data bytes to send + * param size The number of data bytes to send + * retval kStatus_Success write success without error + * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout + * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequencen error detected + * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected + */ +status_t FLEXSPI_WriteBlocking(FLEXSPI_Type *base, uint32_t *buffer, size_t size) +{ + uint8_t txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1; + uint32_t status; + status_t result = kStatus_Success; + uint32_t i = 0; + + /* Send data buffer */ + while (size) + { + /* Wait until there is room in the fifo. This also checks for errors. */ + while (!((status = base->INTR) & kFLEXSPI_IpTxFifoWatermarkEmpltyFlag)) + { + } + + result = FLEXSPI_CheckAndClearError(base, status); + + if (result) + { + return result; + } + + /* Write watermark level data into tx fifo . */ + if (size >= 8 * txWatermark) + { + for (i = 0; i < 2 * txWatermark; i++) + { + base->TFDR[i] = *buffer++; + } + + size = size - 8 * txWatermark; + } + else + { + for (i = 0; i < (size / 4 + 1); i++) + { + base->TFDR[i] = *buffer++; + } + size = 0; + } + + /* Push a watermark level datas into IP TX FIFO. */ + base->INTR |= kFLEXSPI_IpTxFifoWatermarkEmpltyFlag; + } + + return result; +} + +/*! + * brief Receives a buffer of data bytes using a blocking method. + * note This function blocks via polling until all bytes have been sent. + * param base FLEXSPI peripheral base address + * param buffer The data bytes to send + * param size The number of data bytes to receive + * retval kStatus_Success read success without error + * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout + * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequencen error detected + * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected + */ +status_t FLEXSPI_ReadBlocking(FLEXSPI_Type *base, uint32_t *buffer, size_t size) +{ + uint8_t rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1; + uint32_t status; + status_t result = kStatus_Success; + uint32_t i = 0; + + /* Send data buffer */ + while (size) + { + if (size >= 8 * rxWatermark) + { + /* Wait until there is room in the fifo. This also checks for errors. */ + while (!((status = base->INTR) & kFLEXSPI_IpRxFifoWatermarkAvailableFlag)) + { + result = FLEXSPI_CheckAndClearError(base, status); + + if (result) + { + return result; + } + } + } + else + { + /* Wait fill level. This also checks for errors. */ + while (size > ((((base->IPRXFSTS) & FLEXSPI_IPRXFSTS_FILL_MASK) >> FLEXSPI_IPRXFSTS_FILL_SHIFT) * 8U)) + { + result = FLEXSPI_CheckAndClearError(base, base->INTR); + + if (result) + { + return result; + } + } + } + + result = FLEXSPI_CheckAndClearError(base, base->INTR); + + if (result) + { + return result; + } + + /* Read watermark level data from rx fifo . */ + if (size >= 8 * rxWatermark) + { + for (i = 0; i < 2 * rxWatermark; i++) + { + *buffer++ = base->RFDR[i]; + } + + size = size - 8 * rxWatermark; + } + else + { + for (i = 0; i < (size / 4 + 1); i++) + { + *buffer++ = base->RFDR[i]; + } + size = 0; + } + + /* Pop out a watermark level datas from IP RX FIFO. */ + base->INTR |= kFLEXSPI_IpRxFifoWatermarkAvailableFlag; + } + + return result; +} + +/*! + * brief Execute command to transfer a buffer data bytes using a blocking method. + * param base FLEXSPI peripheral base address + * param xfer pointer to the transfer structure. + * retval kStatus_Success command transfer success without error + * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout + * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequencen error detected + * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected + */ +status_t FLEXSPI_TransferBlocking(FLEXSPI_Type *base, flexspi_transfer_t *xfer) +{ + uint32_t configValue = 0; + status_t result = kStatus_Success; + + /* Clear sequence pointer before sending data to external devices. */ + base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK; + + /* Clear former pending status before start this transfer. */ + base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK | + FLEXSPI_INTR_IPCMDGE_MASK; + + /* Configure base address. */ + base->IPCR0 = xfer->deviceAddress; + + /* Reset fifos. */ + base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK; + base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK; + + /* Configure data size. */ + if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config)) + { + configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize); + } + + /* Configure sequence ID. */ + configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM(xfer->SeqNumber - 1); + base->IPCR1 = configValue; + + /* Start Transfer. */ + base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK; + + if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config)) + { + result = FLEXSPI_WriteBlocking(base, xfer->data, xfer->dataSize); + } + else if (xfer->cmdType == kFLEXSPI_Read) + { + result = FLEXSPI_ReadBlocking(base, xfer->data, xfer->dataSize); + } + else + { + } + + /* Wait for bus idle. */ + while (!FLEXSPI_GetBusIdleStatus(base)) + { + } + + if (xfer->cmdType == kFLEXSPI_Command) + { + result = FLEXSPI_CheckAndClearError(base, base->INTR); + } + + return result; +} + +/*! + * brief Initializes the FLEXSPI handle which is used in transactional functions. + * + * param base FLEXSPI peripheral base address. + * param handle pointer to flexspi_handle_t structure to store the transfer state. + * param callback pointer to user callback function. + * param userData user parameter passed to the callback function. + */ +void FLEXSPI_TransferCreateHandle(FLEXSPI_Type *base, + flexspi_handle_t *handle, + flexspi_transfer_callback_t callback, + void *userData) +{ + assert(handle); + + uint32_t instance = FLEXSPI_GetInstance(base); + + /* Zero handle. */ + memset(handle, 0, sizeof(*handle)); + + /* Set callback and userData. */ + handle->completionCallback = callback; + handle->userData = userData; + +#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ + /* Save the context in global variables to support the double weak mechanism. */ + s_flexspiHandle[instance] = handle; +#endif + + /* Enable NVIC interrupt. */ + EnableIRQ(s_flexspiIrqs[instance]); +} + +/*! + * brief Performs a interrupt non-blocking transfer on the FLEXSPI bus. + * + * note Calling the API returns immediately after transfer initiates. The user needs + * to call FLEXSPI_GetTransferCount to poll the transfer status to check whether + * the transfer is finished. If the return status is not kStatus_FLEXSPI_Busy, the transfer + * is finished. For FLEXSPI_Read, the dataSize should be multiple of rx watermark levle, or + * FLEXSPI could not read data properly. + * + * param base FLEXSPI peripheral base address. + * param handle pointer to flexspi_handle_t structure which stores the transfer state. + * param xfer pointer to flexspi_transfer_t structure. + * retval kStatus_Success Successfully start the data transmission. + * retval kStatus_FLEXSPI_Busy Previous transmission still not finished. + */ +status_t FLEXSPI_TransferNonBlocking(FLEXSPI_Type *base, flexspi_handle_t *handle, flexspi_transfer_t *xfer) +{ + uint32_t configValue = 0; + status_t result = kStatus_Success; + + assert(handle); + assert(xfer); + + /* Check if the I2C bus is idle - if not return busy status. */ + if (handle->state != kFLEXSPI_Idle) + { + result = kStatus_FLEXSPI_Busy; + } + else + { + handle->data = xfer->data; + handle->dataSize = xfer->dataSize; + handle->transferTotalSize = xfer->dataSize; + handle->state = (xfer->cmdType == kFLEXSPI_Read) ? kFLEXSPI_BusyRead : kFLEXSPI_BusyWrite; + + /* Clear sequence pointer before sending data to external devices. */ + base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK; + + /* Clear former pending status before start this transfer. */ + base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK | + FLEXSPI_INTR_IPCMDGE_MASK; + + /* Configure base address. */ + base->IPCR0 = xfer->deviceAddress; + + /* Reset fifos. */ + base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK; + base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK; + + /* Configure data size. */ + if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write)) + { + configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize); + } + + /* Configure sequence ID. */ + configValue |= FLEXSPI_IPCR1_ISEQID(xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM(xfer->SeqNumber - 1); + base->IPCR1 = configValue; + + /* Start Transfer. */ + base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK; + + if (handle->state == kFLEXSPI_BusyRead) + { + FLEXSPI_EnableInterrupts(base, kFLEXSPI_IpRxFifoWatermarkAvailableFlag | + kFLEXSPI_SequenceExecutionTimeoutFlag | + kFLEXSPI_IpCommandSequenceErrorFlag | + kFLEXSPI_IpCommandGrantTimeoutFlag | kFLEXSPI_IpCommandExcutionDoneFlag); + } + else + { + FLEXSPI_EnableInterrupts(base, kFLEXSPI_IpTxFifoWatermarkEmpltyFlag | + kFLEXSPI_SequenceExecutionTimeoutFlag | + kFLEXSPI_IpCommandSequenceErrorFlag | + kFLEXSPI_IpCommandGrantTimeoutFlag | kFLEXSPI_IpCommandExcutionDoneFlag); + } + } + + return result; +} + +/*! + * brief Gets the master transfer status during a interrupt non-blocking transfer. + * + * param base FLEXSPI peripheral base address. + * param handle pointer to flexspi_handle_t structure which stores the transfer state. + * param count Number of bytes transferred so far by the non-blocking transaction. + * retval kStatus_InvalidArgument count is Invalid. + * retval kStatus_Success Successfully return the count. + */ +status_t FLEXSPI_TransferGetCount(FLEXSPI_Type *base, flexspi_handle_t *handle, size_t *count) +{ + assert(handle); + + status_t result = kStatus_Success; + + if (handle->state == kFLEXSPI_Idle) + { + result = kStatus_NoTransferInProgress; + } + else + { + *count = handle->transferTotalSize - handle->dataSize; + } + + return result; +} + +/*! + * brief Aborts an interrupt non-blocking transfer early. + * + * note This API can be called at any time when an interrupt non-blocking transfer initiates + * to abort the transfer early. + * + * param base FLEXSPI peripheral base address. + * param handle pointer to flexspi_handle_t structure which stores the transfer state + */ +void FLEXSPI_TransferAbort(FLEXSPI_Type *base, flexspi_handle_t *handle) +{ + assert(handle); + + FLEXSPI_DisableInterrupts(base, kIrqFlags); + handle->state = kFLEXSPI_Idle; +} + +/*! + * brief Master interrupt handler. + * + * param base FLEXSPI peripheral base address. + * param handle pointer to flexspi_handle_t structure. + */ +void FLEXSPI_TransferHandleIRQ(FLEXSPI_Type *base, flexspi_handle_t *handle) +{ + uint32_t status; + status_t result; + uint32_t intEnableStatus; + uint8_t txWatermark; + uint8_t rxWatermark; + uint8_t i = 0; + + status = base->INTR; + intEnableStatus = base->INTEN; + + /* Check if interrupt is enabled and status is alerted. */ + if ((status & intEnableStatus) == 0U) + { + return; + } + + result = FLEXSPI_CheckAndClearError(base, status); + + if ((result != kStatus_Success) && (handle->completionCallback != NULL)) + { + FLEXSPI_TransferAbort(base, handle); + if (handle->completionCallback) + { + handle->completionCallback(base, handle, result, handle->userData); + } + return; + } + + if ((status & kFLEXSPI_IpRxFifoWatermarkAvailableFlag) && (handle->state == kFLEXSPI_BusyRead)) + { + rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1; + + /* Read watermark level data from rx fifo . */ + if (handle->dataSize >= 8 * rxWatermark) + { + /* Read watermark level data from rx fifo . */ + for (i = 0; i < 2 * rxWatermark; i++) + { + *handle->data++ = base->RFDR[i]; + } + + handle->dataSize = handle->dataSize - 8 * rxWatermark; + } + else + { + for (i = 0; i < (handle->dataSize / 4 + 1); i++) + { + *handle->data++ = base->RFDR[i]; + } + handle->dataSize = 0; + } + /* Pop out a watermark level datas from IP RX FIFO. */ + base->INTR |= kFLEXSPI_IpRxFifoWatermarkAvailableFlag; + } + + if (status & kFLEXSPI_IpCommandExcutionDoneFlag) + { + base->INTR |= kFLEXSPI_IpCommandExcutionDoneFlag; + + FLEXSPI_TransferAbort(base, handle); + + if (handle->completionCallback) + { + handle->completionCallback(base, handle, kStatus_Success, handle->userData); + } + } + + /* TX FIFO empty interrupt, push watermark level data into tx FIFO. */ + if ((status & kFLEXSPI_IpTxFifoWatermarkEmpltyFlag) && (handle->state == kFLEXSPI_BusyWrite)) + { + if (handle->dataSize) + { + txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1; + /* Write watermark level data into tx fifo . */ + if (handle->dataSize >= 8 * txWatermark) + { + for (i = 0; i < 2 * txWatermark; i++) + { + base->TFDR[i] = *handle->data++; + } + + handle->dataSize = handle->dataSize - 8 * txWatermark; + } + else + { + for (i = 0; i < (handle->dataSize / 4 + 1); i++) + { + base->TFDR[i] = *handle->data++; + } + handle->dataSize = 0; + } + + /* Push a watermark level datas into IP TX FIFO. */ + base->INTR |= kFLEXSPI_IpTxFifoWatermarkEmpltyFlag; + } + } + else + { + } +} + +#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ +#if defined(FLEXSPI) +void FLEXSPI_DriverIRQHandler(void) +{ + FLEXSPI_TransferHandleIRQ(FLEXSPI, s_flexspiHandle[0]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif + +#if defined(FLEXSPI0) +void FLEXSPI0_DriverIRQHandler(void) +{ + FLEXSPI_TransferHandleIRQ(FLEXSPI0, s_flexspiHandle[0]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif +#if defined(FLEXSPI1) +void FLEXSPI1_DriverIRQHandler(void) +{ + FLEXSPI_TransferHandleIRQ(FLEXSPI1, s_flexspiHandle[1]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif + +#if defined(LSIO__FLEXSPI0) +void LSIO_OCTASPI0_INT_DriverIRQHandler(void) +{ + FLEXSPI_TransferHandleIRQ(LSIO__FLEXSPI0, s_flexspiHandle[0]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif +#if defined(LSIO__FLEXSPI1) +void LSIO_OCTASPI1_INT_DriverIRQHandler(void) +{ + FLEXSPI_TransferHandleIRQ(LSIO__FLEXSPI1, s_flexspiHandle[1]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif + +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_flexspi.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_flexspi.h new file mode 100755 index 000000000..908519875 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_flexspi.h @@ -0,0 +1,831 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __FSL_FLEXSPI_H_ +#define __FSL_FLEXSPI_H_ + +#include +#include "fsl_device_registers.h" +#include "fsl_common.h" + +#define spi_print KPrintf +#define spi_trace() KPrintf("lw: [%s][%d] passed!\n", __func__, __LINE__) + +/*! + * @addtogroup flexspi + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief FLEXSPI driver version 2.1.1. */ +#define FSL_FLEXSPI_DRIVER_VERSION (MAKE_VERSION(2, 1, 1)) +/*@}*/ + +#define FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNTn(0) + +/*! @breif Formula to form FLEXSPI instructions in LUT table. */ +#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ + FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + +/*! @brief Status structure of FLEXSPI.*/ +enum _flexspi_status +{ + kStatus_FLEXSPI_Busy = MAKE_STATUS(kStatusGroup_FLEXSPI, 0), /*!< FLEXSPI is busy */ + kStatus_FLEXSPI_SequenceExecutionTimeout = MAKE_STATUS(kStatusGroup_FLEXSPI, 1), /*!< Sequence execution timeout + error occurred during FLEXSPI transfer. */ + kStatus_FLEXSPI_IpCommandSequenceError = MAKE_STATUS(kStatusGroup_FLEXSPI, 2), /*!< IP command Sequence execution + timeout error occurred during FLEXSPI transfer. */ + kStatus_FLEXSPI_IpCommandGrantTimeout = MAKE_STATUS(kStatusGroup_FLEXSPI, 3), /*!< IP command grant timeout error + occurred during FLEXSPI transfer. */ +}; + +/*! @brief CMD definition of FLEXSPI, use to form LUT instruction. */ +enum _flexspi_command +{ + kFLEXSPI_Command_STOP = 0x00U, /*!< Stop execution, deassert CS. */ + kFLEXSPI_Command_SDR = 0x01U, /*!< Transmit Command code to Flash, using SDR mode. */ + kFLEXSPI_Command_RADDR_SDR = 0x02U, /*!< Transmit Row Address to Flash, using SDR mode. */ + kFLEXSPI_Command_CADDR_SDR = 0x03U, /*!< Transmit Column Address to Flash, using SDR mode. */ + kFLEXSPI_Command_MODE1_SDR = 0x04U, /*!< Transmit 1-bit Mode bits to Flash, using SDR mode. */ + kFLEXSPI_Command_MODE2_SDR = 0x05U, /*!< Transmit 2-bit Mode bits to Flash, using SDR mode. */ + kFLEXSPI_Command_MODE4_SDR = 0x06U, /*!< Transmit 4-bit Mode bits to Flash, using SDR mode. */ + kFLEXSPI_Command_MODE8_SDR = 0x07U, /*!< Transmit 8-bit Mode bits to Flash, using SDR mode. */ + kFLEXSPI_Command_WRITE_SDR = 0x08U, /*!< Transmit Programming Data to Flash, using SDR mode. */ + kFLEXSPI_Command_READ_SDR = 0x09U, /*!< Receive Read Data from Flash, using SDR mode. */ + kFLEXSPI_Command_LEARN_SDR = 0x0AU, /*!< Receive Read Data or Preamble bit from Flash, SDR mode. */ + kFLEXSPI_Command_DATSZ_SDR = 0x0BU, /*!< Transmit Read/Program Data size (byte) to Flash, SDR mode. */ + kFLEXSPI_Command_DUMMY_SDR = 0x0CU, /*!< Leave data lines undriven by FlexSPI controller.*/ + kFLEXSPI_Command_DUMMY_RWDS_SDR = 0x0DU, /*!< Leave data lines undriven by FlexSPI controller, + dummy cycles decided by RWDS. */ + kFLEXSPI_Command_DDR = 0x21U, /*!< Transmit Command code to Flash, using DDR mode. */ + kFLEXSPI_Command_RADDR_DDR = 0x22U, /*!< Transmit Row Address to Flash, using DDR mode. */ + kFLEXSPI_Command_CADDR_DDR = 0x23U, /*!< Transmit Column Address to Flash, using DDR mode. */ + kFLEXSPI_Command_MODE1_DDR = 0x24U, /*!< Transmit 1-bit Mode bits to Flash, using DDR mode. */ + kFLEXSPI_Command_MODE2_DDR = 0x25U, /*!< Transmit 2-bit Mode bits to Flash, using DDR mode. */ + kFLEXSPI_Command_MODE4_DDR = 0x26U, /*!< Transmit 4-bit Mode bits to Flash, using DDR mode. */ + kFLEXSPI_Command_MODE8_DDR = 0x27U, /*!< Transmit 8-bit Mode bits to Flash, using DDR mode. */ + kFLEXSPI_Command_WRITE_DDR = 0x28U, /*!< Transmit Programming Data to Flash, using DDR mode. */ + kFLEXSPI_Command_READ_DDR = 0x29U, /*!< Receive Read Data from Flash, using DDR mode. */ + kFLEXSPI_Command_LEARN_DDR = 0x2AU, /*!< Receive Read Data or Preamble bit from Flash, DDR mode. */ + kFLEXSPI_Command_DATSZ_DDR = 0x2BU, /*!< Transmit Read/Program Data size (byte) to Flash, DDR mode. */ + kFLEXSPI_Command_DUMMY_DDR = 0x2CU, /*!< Leave data lines undriven by FlexSPI controller.*/ + kFLEXSPI_Command_DUMMY_RWDS_DDR = 0x2DU, /*!< Leave data lines undriven by FlexSPI controller, + dummy cycles decided by RWDS. */ + kFLEXSPI_Command_JUMP_ON_CS = 0x1FU, /*!< Stop execution, deassert CS and save operand[7:0] as the + instruction start pointer for next sequence */ +}; + +/*! @brief pad definition of FLEXSPI, use to form LUT instruction. */ +typedef enum _flexspi_pad +{ + kFLEXSPI_1PAD = 0x00U, /*!< Transmit command/address and transmit/receive data only through DATA0/DATA1. */ + kFLEXSPI_2PAD = 0x01U, /*!< Transmit command/address and transmit/receive data only through DATA[1:0]. */ + kFLEXSPI_4PAD = 0x02U, /*!< Transmit command/address and transmit/receive data only through DATA[3:0]. */ + kFLEXSPI_8PAD = 0x03U, /*!< Transmit command/address and transmit/receive data only through DATA[7:0]. */ +} flexspi_pad_t; + +/*! @brief FLEXSPI interrupt status flags.*/ +typedef enum _flexspi_flags +{ + kFLEXSPI_SequenceExecutionTimeoutFlag = FLEXSPI_INTEN_SEQTIMEOUTEN_MASK, /*!< Sequence execution timeout. */ + kFLEXSPI_AhbBusTimeoutFlag = FLEXSPI_INTEN_AHBBUSTIMEOUTEN_MASK, /*!< AHB Bus timeout. */ + kFLEXSPI_SckStoppedBecauseTxEmptyFlag = + FLEXSPI_INTEN_SCKSTOPBYWREN_MASK, /*!< SCK is stopped during command + sequence because Async TX FIFO empty. */ + kFLEXSPI_SckStoppedBecauseRxFullFlag = + FLEXSPI_INTEN_SCKSTOPBYRDEN_MASK, /*!< SCK is stopped during command + sequence because Async RX FIFO full. */ +#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_DATA_LEARN)) && (FSL_FEATURE_FLEXSPI_HAS_NO_DATA_LEARN)) + kFLEXSPI_DataLearningFailedFlag = FLEXSPI_INTEN_DATALEARNFAILEN_MASK, /*!< Data learning failed. */ +#endif + kFLEXSPI_IpTxFifoWatermarkEmpltyFlag = FLEXSPI_INTEN_IPTXWEEN_MASK, /*!< IP TX FIFO WaterMark empty. */ + kFLEXSPI_IpRxFifoWatermarkAvailableFlag = FLEXSPI_INTEN_IPRXWAEN_MASK, /*!< IP RX FIFO WaterMark available. */ + kFLEXSPI_AhbCommandSequenceErrorFlag = + FLEXSPI_INTEN_AHBCMDERREN_MASK, /*!< AHB triggered Command Sequences Error. */ + kFLEXSPI_IpCommandSequenceErrorFlag = FLEXSPI_INTEN_IPCMDERREN_MASK, /*!< IP triggered Command Sequences Error. */ + kFLEXSPI_AhbCommandGrantTimeoutFlag = + FLEXSPI_INTEN_AHBCMDGEEN_MASK, /*!< AHB triggered Command Sequences Grant Timeout. */ + kFLEXSPI_IpCommandGrantTimeoutFlag = + FLEXSPI_INTEN_IPCMDGEEN_MASK, /*!< IP triggered Command Sequences Grant Timeout. */ + kFLEXSPI_IpCommandExcutionDoneFlag = + FLEXSPI_INTEN_IPCMDDONEEN_MASK, /*!< IP triggered Command Sequences Execution finished. */ + kFLEXSPI_AllInterruptFlags = 0xFFFU, /*!< All flags. */ +} flexspi_flags_t; + +/*! @brief FLEXSPI sample clock source selection for Flash Reading.*/ +typedef enum _flexspi_read_sample_clock +{ + kFLEXSPI_ReadSampleClkLoopbackInternally = 0x0U, /*!< Dummy Read strobe generated by FlexSPI Controller + and loopback internally. */ + kFLEXSPI_ReadSampleClkLoopbackFromDqsPad = 0x1U, /*!< Dummy Read strobe generated by FlexSPI Controller + and loopback from DQS pad. */ + kFLEXSPI_ReadSampleClkLoopbackFromSckPad = 0x2U, /*!< SCK output clock and loopback from SCK pad. */ + kFLEXSPI_ReadSampleClkExternalInputFromDqsPad = 0x3U, /*!< Flash provided Read strobe and input from DQS pad. */ +} flexspi_read_sample_clock_t; + +/*! @brief FLEXSPI interval unit for flash device select.*/ +typedef enum _flexspi_cs_interval_cycle_unit +{ + kFLEXSPI_CsIntervalUnit1SckCycle = 0x0U, /*!< Chip selection interval: CSINTERVAL * 1 serial clock cycle. */ + kFLEXSPI_CsIntervalUnit256SckCycle = 0x1U, /*!< Chip selection interval: CSINTERVAL * 256 serial clock cycle. */ +} flexspi_cs_interval_cycle_unit_t; + +/*! @brief FLEXSPI AHB wait interval unit for writting.*/ +typedef enum _flexspi_ahb_write_wait_unit +{ + kFLEXSPI_AhbWriteWaitUnit2AhbCycle = 0x0U, /*!< AWRWAIT unit is 2 ahb clock cycle. */ + kFLEXSPI_AhbWriteWaitUnit8AhbCycle = 0x1U, /*!< AWRWAIT unit is 8 ahb clock cycle. */ + kFLEXSPI_AhbWriteWaitUnit32AhbCycle = 0x2U, /*!< AWRWAIT unit is 32 ahb clock cycle. */ + kFLEXSPI_AhbWriteWaitUnit128AhbCycle = 0x3U, /*!< AWRWAIT unit is 128 ahb clock cycle. */ + kFLEXSPI_AhbWriteWaitUnit512AhbCycle = 0x4U, /*!< AWRWAIT unit is 512 ahb clock cycle. */ + kFLEXSPI_AhbWriteWaitUnit2048AhbCycle = 0x5U, /*!< AWRWAIT unit is 2048 ahb clock cycle. */ + kFLEXSPI_AhbWriteWaitUnit8192AhbCycle = 0x6U, /*!< AWRWAIT unit is 8192 ahb clock cycle. */ + kFLEXSPI_AhbWriteWaitUnit32768AhbCycle = 0x7U, /*!< AWRWAIT unit is 32768 ahb clock cycle. */ +} flexspi_ahb_write_wait_unit_t; + +/*! @brief Error Code when IP command Error detected.*/ +typedef enum _flexspi_ip_error_code +{ + kFLEXSPI_IpCmdErrorNoError = 0x0U, /*!< No error. */ + kFLEXSPI_IpCmdErrorJumpOnCsInIpCmd = 0x2U, /*!< IP command with JMP_ON_CS instruction used. */ + kFLEXSPI_IpCmdErrorUnknownOpCode = 0x3U, /*!< Unknown instruction opcode in the sequence. */ + kFLEXSPI_IpCmdErrorSdrDummyInDdrSequence = 0x4U, /*!< Instruction DUMMY_SDR/DUMMY_RWDS_SDR + used in DDR sequence. */ + kFLEXSPI_IpCmdErrorDdrDummyInSdrSequence = 0x5U, /*!< Instruction DUMMY_DDR/DUMMY_RWDS_DDR + used in SDR sequence. */ + kFLEXSPI_IpCmdErrorInvalidAddress = 0x6U, /*!< Flash access start address exceed the whole + flash address range (A1/A2/B1/B2). */ + kFLEXSPI_IpCmdErrorSequenceExecutionTimeout = 0xEU, /*!< Sequence execution timeout. */ + kFLEXSPI_IpCmdErrorFlashBoundaryAcrosss = 0xFU, /*!< Flash boundary crossed. */ +} flexspi_ip_error_code_t; + +/*! @brief Error Code when AHB command Error detected.*/ +typedef enum _flexspi_ahb_error_code +{ + kFLEXSPI_AhbCmdErrorNoError = 0x0U, /*!< No error. */ + kFLEXSPI_AhbCmdErrorJumpOnCsInWriteCmd = 0x2U, /*!< AHB Write command with JMP_ON_CS instruction + used in the sequence. */ + kFLEXSPI_AhbCmdErrorUnknownOpCode = 0x3U, /*!< Unknown instruction opcode in the sequence. */ + kFLEXSPI_AhbCmdErrorSdrDummyInDdrSequence = 0x4U, /*!< Instruction DUMMY_SDR/DUMMY_RWDS_SDR used + in DDR sequence. */ + kFLEXSPI_AhbCmdErrorDdrDummyInSdrSequence = 0x5U, /*!< Instruction DUMMY_DDR/DUMMY_RWDS_DDR + used in SDR sequence. */ + kFLEXSPI_AhbCmdSequenceExecutionTimeout = 0x6U, /*!< Sequence execution timeout. */ +} flexspi_ahb_error_code_t; + +/*! @brief FLEXSPI operation port select.*/ +typedef enum _flexspi_port +{ + kFLEXSPI_PortA1 = 0x0U, /*!< Access flash on A1 port. */ + kFLEXSPI_PortA2, /*!< Access flash on A2 port. */ + kFLEXSPI_PortB1, /*!< Access flash on B1 port. */ + kFLEXSPI_PortB2, /*!< Access flash on B2 port. */ + kFLEXSPI_PortCount +} flexspi_port_t; + +/*! @brief Trigger source of current command sequence granted by arbitrator.*/ +typedef enum _flexspi_arb_command_source +{ + kFLEXSPI_AhbReadCommand = 0x0U, + kFLEXSPI_AhbWriteCommand = 0x1U, + kFLEXSPI_IpCommand = 0x2U, + kFLEXSPI_SuspendedCommand = 0x3U, +} flexspi_arb_command_source_t; + +typedef enum _flexspi_command_type +{ + kFLEXSPI_Command, /*!< FlexSPI operation: Only command, both TX and Rx buffer are ignored. */ + kFLEXSPI_Config, /*!< FlexSPI operation: Configure device mode, the TX fifo size is fixed in LUT. */ + kFLEXSPI_Read, /* /!< FlexSPI operation: Read, only Rx Buffer is effective. */ + kFLEXSPI_Write, /* /!< FlexSPI operation: Read, only Tx Buffer is effective. */ +} flexspi_command_type_t; + +typedef struct _flexspi_ahbBuffer_config +{ + uint8_t priority; /*!< This priority for AHB Master Read which this AHB RX Buffer is assigned. */ + uint8_t masterIndex; /*!< AHB Master ID the AHB RX Buffer is assigned. */ + uint16_t bufferSize; /*!< AHB buffer size in byte. */ + bool enablePrefetch; /*!< AHB Read Prefetch Enable for current AHB RX Buffer corresponding Master, allows + prefetch disable/enable seperately for each master. */ +} flexspi_ahbBuffer_config_t; + +/*! @brief FLEXSPI configuration structure. */ +typedef struct _flexspi_config +{ + flexspi_read_sample_clock_t rxSampleClock; /*!< Sample Clock source selection for Flash Reading. */ + bool enableSckFreeRunning; /*!< Enable/disable SCK output free-running. */ + bool enableCombination; /*!< Enable/disable combining PORT A and B Data Pins + (SIOA[3:0] and SIOB[3:0]) to support Flash Octal mode. */ + bool enableDoze; /*!< Enable/disable doze mode support. */ + bool enableHalfSpeedAccess; /*!< Enable/disable divide by 2 of the clock for half + speed commands. */ + bool enableSckBDiffOpt; /*!< Enable/disable SCKB pad use as SCKA differential clock + output, when enable, Port B flash access is not available. */ + bool enableSameConfigForAll; /*!< Enable/disable same configuration for all connected devices + when enabled, same configuration in FLASHA1CRx is applied to all. */ + uint16_t seqTimeoutCycle; /*!< Timeout wait cycle for command sequence execution, + timeout after ahbGrantTimeoutCyle*1024 serial root clock cycles. */ + uint8_t ipGrantTimeoutCycle; /*!< Timeout wait cycle for IP command grant, timeout after + ipGrantTimeoutCycle*1024 AHB clock cycles. */ + uint8_t txWatermark; /*!< FLEXSPI IP transmit watermark value. */ + uint8_t rxWatermark; /*!< FLEXSPI receive watermark value. */ + struct + { + bool enableAHBWriteIpTxFifo; /*!< Enable AHB bus write access to IP TX FIFO. */ + bool enableAHBWriteIpRxFifo; /*!< Enable AHB bus write access to IP RX FIFO. */ + uint8_t ahbGrantTimeoutCycle; /*!< Timeout wait cycle for AHB command grant, + timeout after ahbGrantTimeoutCyle*1024 AHB clock cycles. */ + uint16_t ahbBusTimeoutCycle; /*!< Timeout wait cycle for AHB read/write access, + timeout after ahbBusTimeoutCycle*1024 AHB clock cycles. */ + uint8_t resumeWaitCycle; /*!< Wait cycle for idle state before suspended command sequence + resume, timeout after ahbBusTimeoutCycle AHB clock cycles. */ + flexspi_ahbBuffer_config_t buffer[FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT]; /*!< AHB buffer size. */ + bool enableClearAHBBufferOpt; /*!< Enable/disable automatically clean AHB RX Buffer and TX Buffer + when FLEXSPI returns STOP mode ACK. */ + bool enableReadAddressOpt; /*!< Enable/disable remove AHB read burst start address alignment limitation. + when eanble, there is no AHB read burst start address alignment limitation. */ + bool enableAHBPrefetch; /*!< Enable/disable AHB read prefetch feature, when enabled, FLEXSPI + will fetch more data than current AHB burst. */ + bool enableAHBBufferable; /*!< Enable/disable AHB bufferable write access support, when enabled, + FLEXSPI return before waiting for command excution finished. */ + bool enableAHBCachable; /*!< Enable AHB bus cachable read access support. */ + } ahbConfig; +} flexspi_config_t; + +/*! @brief External device configuration items. */ +typedef struct _flexspi_device_config +{ + uint32_t flexspiRootClk; /*!< FLEXSPI serial root clock. */ + bool isSck2Enabled; /*!< FLEXSPI use SCK2. */ + uint32_t flashSize; /*!< Flash size in KByte. */ + flexspi_cs_interval_cycle_unit_t CSIntervalUnit; /*!< CS interval unit, 1 or 256 cycle. */ + uint16_t CSInterval; /*!< CS line assert interval, mutiply CS interval unit to + get the CS line assert interval cycles. */ + uint8_t CSHoldTime; /*!< CS line hold time. */ + uint8_t CSSetupTime; /*!< CS line setup time. */ + uint8_t dataValidTime; /*!< Data valid time for external device. */ + uint8_t columnspace; /*!< Column space size. */ + bool enableWordAddress; /*!< If enable word address.*/ + uint8_t AWRSeqIndex; /*!< Sequence ID for AHB write command. */ + uint8_t AWRSeqNumber; /*!< Sequence number for AHB write command. */ + uint8_t ARDSeqIndex; /*!< Sequence ID for AHB read command. */ + uint8_t ARDSeqNumber; /*!< Sequence number for AHB read command. */ + flexspi_ahb_write_wait_unit_t AHBWriteWaitUnit; /*!< AHB write wait unit. */ + uint16_t AHBWriteWaitInterval; /*!< AHB write wait interval, mutiply AHB write interval + unit to get the AHB write wait cycles. */ + bool enableWriteMask; /*!< Enable/Disable FLEXSPI drive DQS pin as write mask + when writing to external device. */ +} flexspi_device_config_t; + +/*! @brief Transfer structure for FLEXSPI. */ +typedef struct _flexspi_transfer +{ + uint32_t deviceAddress; /*!< Operation device address. */ + flexspi_port_t port; /*!< Operation port. */ + flexspi_command_type_t cmdType; /*!< Execution command type. */ + uint8_t seqIndex; /*!< Sequence ID for command. */ + uint8_t SeqNumber; /*!< Sequence number for command. */ + uint32_t *data; /*!< Data buffer. */ + size_t dataSize; /*!< Data size in bytes. */ +} flexspi_transfer_t; + +/* Forward declaration of the handle typedef. */ +typedef struct _flexspi_handle flexspi_handle_t; + +/*! @brief FLEXSPI transfer callback function. */ +typedef void (*flexspi_transfer_callback_t)(FLEXSPI_Type *base, + flexspi_handle_t *handle, + status_t status, + void *userData); + +/*! @brief Transfer handle structure for FLEXSPI. */ +struct _flexspi_handle +{ + uint32_t state; /*!< Internal state for FLEXSPI transfer */ + uint32_t *data; /*!< Data buffer. */ + size_t dataSize; /*!< Remaining Data size in bytes. */ + size_t transferTotalSize; /*!< Total Data size in bytes. */ + flexspi_transfer_callback_t completionCallback; /*!< Callback for users while transfer finish or error occurred */ + void *userData; /*!< FLEXSPI callback function parameter.*/ +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /*_cplusplus. */ + +/*! + * @name Initialization and deinitialization + * @{ + */ +/*! + * @brief Initializes the FLEXSPI module and internal state. + * + * This function enables the clock for FLEXSPI and also configures the FLEXSPI with the + * input configure parameters. Users should call this function before any FLEXSPI operations. + * + * @param base FLEXSPI peripheral base address. + * @param config FLEXSPI configure structure. + */ +void FLEXSPI_Init(FLEXSPI_Type *base, const flexspi_config_t *config); + +/*! + * @brief Gets default settings for FLEXSPI. + * + * @param config FLEXSPI configuration structure. + */ +void FLEXSPI_GetDefaultConfig(flexspi_config_t *config); + +/*! + * @brief Deinitializes the FLEXSPI module. + * + * Clears the FLEXSPI state and FLEXSPI module registers. + * @param base FLEXSPI peripheral base address. + */ +void FLEXSPI_Deinit(FLEXSPI_Type *base); + +/*! + * @brief Configures the connected device parameter. + * + * This function configures the connected device relevant parameters, such as the size, command, and so on. + * The flash configuration value cannot have a default value. The user needs to configure it according to the + * connected device. + * + * @param base FLEXSPI peripheral base address. + * @param config Flash configuration parameters. + * @param port FLEXSPI Operation port. + */ +void FLEXSPI_SetFlashConfig(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port); + +/*! + * @brief Software reset for the FLEXSPI logic. + * + * This function sets the software reset flags for both AHB and buffer domain and + * resets both AHB buffer and also IP FIFOs. + * + * @param base FLEXSPI peripheral base address. + */ +static inline void FLEXSPI_SoftwareReset(FLEXSPI_Type *base) +{ +//tst by wly + return; + base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK; + while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) + { + } +} + +/*! + * @brief Enables or disables the FLEXSPI module. + * + * @param base FLEXSPI peripheral base address. + * @param enable True means enable FLEXSPI, false means disable. + */ +static inline void FLEXSPI_Enable(FLEXSPI_Type *base, bool enable) +{ + if (enable) + { + base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK; + } + else + { + base->MCR0 |= FLEXSPI_MCR0_MDIS_MASK; + } +} + +/* @} */ + +/*! + * @name Interrupts + * @{ + */ +/*! + * @brief Enables the FLEXSPI interrupts. + * + * @param base FLEXSPI peripheral base address. + * @param mask FLEXSPI interrupt source. + */ +static inline void FLEXSPI_EnableInterrupts(FLEXSPI_Type *base, uint32_t mask) +{ + base->INTEN |= mask; +} + +/*! + * @brief Disable the FLEXSPI interrupts. + * + * @param base FLEXSPI peripheral base address. + * @param mask FLEXSPI interrupt source. + */ +static inline void FLEXSPI_DisableInterrupts(FLEXSPI_Type *base, uint32_t mask) +{ + base->INTEN &= ~mask; +} + +/* @} */ + +/*! @name DMA control */ +/*@{*/ + +/*! + * @brief Enables or disables FLEXSPI IP Tx FIFO DMA requests. + * + * @param base FLEXSPI peripheral base address. + * @param enable Enable flag for transmit DMA request. Pass true for enable, false for disable. + */ +static inline void FLEXSPI_EnableTxDMA(FLEXSPI_Type *base, bool enable) +{ + if (enable) + { + base->IPTXFCR |= FLEXSPI_IPTXFCR_TXDMAEN_MASK; + } + else + { + base->IPTXFCR &= ~FLEXSPI_IPTXFCR_TXDMAEN_MASK; + } +} + +/*! + * @brief Enables or disables FLEXSPI IP Rx FIFO DMA requests. + * + * @param base FLEXSPI peripheral base address. + * @param enable Enable flag for receive DMA request. Pass true for enable, false for disable. + */ +static inline void FLEXSPI_EnableRxDMA(FLEXSPI_Type *base, bool enable) +{ + if (enable) + { + base->IPRXFCR |= FLEXSPI_IPRXFCR_RXDMAEN_MASK; + } + else + { + base->IPRXFCR &= ~FLEXSPI_IPRXFCR_RXDMAEN_MASK; + } +} + +/*! + * @brief Gets FLEXSPI IP tx fifo address for DMA transfer. + * + * @param base FLEXSPI peripheral base address. + * @retval The tx fifo address. + */ +static inline uint32_t FLEXSPI_GetTxFifoAddress(FLEXSPI_Type *base) +{ + return (uint32_t)&base->TFDR[0]; +} + +/*! + * @brief Gets FLEXSPI IP rx fifo address for DMA transfer. + * + * @param base FLEXSPI peripheral base address. + * @retval The rx fifo address. + */ +static inline uint32_t FLEXSPI_GetRxFifoAddress(FLEXSPI_Type *base) +{ + return (uint32_t)&base->RFDR[0]; +} + +/*@}*/ + +/*! @name FIFO control */ +/*@{*/ + +/*! @brief Clears the FLEXSPI IP FIFO logic. + * + * @param base FLEXSPI peripheral base address. + * @param txFifo Pass true to reset TX FIFO. + * @param rxFifo Pass true to reset RX FIFO. + */ +static inline void FLEXSPI_ResetFifos(FLEXSPI_Type *base, bool txFifo, bool rxFifo) +{ + if (txFifo) + { + base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK; + } + if (rxFifo) + { + base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK; + } +} + +/*! + * @brief Gets the valid data entries in the FLEXSPI FIFOs. + * + * @param base FLEXSPI peripheral base address. + * @param[out] txCount Pointer through which the current number of bytes in the transmit FIFO is returned. + * Pass NULL if this value is not required. + * @param[out] rxCount Pointer through which the current number of bytes in the receive FIFO is returned. + * Pass NULL if this value is not required. + */ +static inline void FLEXSPI_GetFifoCounts(FLEXSPI_Type *base, size_t *txCount, size_t *rxCount) +{ + if (txCount) + { + *txCount = (((base->IPTXFSTS) & FLEXSPI_IPTXFSTS_FILL_MASK) >> FLEXSPI_IPTXFSTS_FILL_SHIFT) * 8U; + } + if (rxCount) + { + *rxCount = (((base->IPRXFSTS) & FLEXSPI_IPRXFSTS_FILL_MASK) >> FLEXSPI_IPRXFSTS_FILL_SHIFT) * 8U; + } +} + +/*@}*/ + +/*! + * @name Status + * @{ + */ +/*! + * @brief Get the FLEXSPI interrupt status flags. + * + * @param base FLEXSPI peripheral base address. + * @retval interrupt status flag, use status flag to AND #flexspi_flags_t could get the related status. + */ +static inline uint32_t FLEXSPI_GetInterruptStatusFlags(FLEXSPI_Type *base) +{ + return base->INTR; +} + +/*! + * @brief Get the FLEXSPI interrupt status flags. + * + * @param base FLEXSPI peripheral base address. + * @param interrupt status flag. + */ +static inline void FLEXSPI_ClearInterruptStatusFlags(FLEXSPI_Type *base, uint32_t mask) +{ + base->INTR |= mask; +} + +#if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_DATA_LEARN)) && (FSL_FEATURE_FLEXSPI_HAS_NO_DATA_LEARN)) +/*! @brief Gets the sampling clock phase selection after Data Learning. + * + * @param base FLEXSPI peripheral base address. + * @param portAPhase Pointer to a uint8_t type variable to receive the selected clock phase on PORTA. + * @param portBPhase Pointer to a uint8_t type variable to receive the selected clock phase on PORTB. + */ +static inline void FLEXSPI_GetDataLearningPhase(FLEXSPI_Type *base, uint8_t *portAPhase, uint8_t *portBPhase) +{ + if (portAPhase) + { + *portAPhase = (base->STS0 & FLEXSPI_STS0_DATALEARNPHASEA_MASK) >> FLEXSPI_STS0_DATALEARNPHASEA_SHIFT; + } + + if (portBPhase) + { + *portBPhase = (base->STS0 & FLEXSPI_STS0_DATALEARNPHASEB_MASK) >> FLEXSPI_STS0_DATALEARNPHASEB_SHIFT; + } +} +#endif + +/*! @brief Gets the trigger source of current command sequence granted by arbitrator. + * + * @param base FLEXSPI peripheral base address. + * @retval trigger source of current command sequence. + */ +static inline flexspi_arb_command_source_t FLEXSPI_GetArbitratorCommandSource(FLEXSPI_Type *base) +{ + return (flexspi_arb_command_source_t)((base->STS0 & FLEXSPI_STS0_ARBCMDSRC_MASK) >> FLEXSPI_STS0_ARBCMDSRC_SHIFT); +} + +/*! @brief Gets the error code when IP command error detected. + * + * @param base FLEXSPI peripheral base address. + * @param index Pointer to a uint8_t type variable to receive the sequence index when error detected. + * @retval error code when IP command error detected. + */ +static inline flexspi_ip_error_code_t FLEXSPI_GetIPCommandErrorCode(FLEXSPI_Type *base, uint8_t *index) +{ + *index = (base->STS1 & FLEXSPI_STS1_IPCMDERRID_MASK) >> FLEXSPI_STS1_IPCMDERRID_SHIFT; + return (flexspi_ip_error_code_t)((base->STS1 & FLEXSPI_STS1_IPCMDERRCODE_MASK) >> FLEXSPI_STS1_IPCMDERRCODE_SHIFT); +} + +/*! @brief Gets the error code when AHB command error detected. + * + * @param base FLEXSPI peripheral base address. + * @param index Pointer to a uint8_t type variable to receive the sequence index when error detected. + * @retval error code when AHB command error detected. + */ +static inline flexspi_ahb_error_code_t FLEXSPI_GetAHBCommandErrorCode(FLEXSPI_Type *base, uint8_t *index) +{ + *index = (base->STS1 & FLEXSPI_STS1_AHBCMDERRID_MASK) >> FLEXSPI_STS1_AHBCMDERRID_SHIFT; + return (flexspi_ahb_error_code_t)((base->STS1 & FLEXSPI_STS1_AHBCMDERRCODE_MASK) >> + FLEXSPI_STS1_AHBCMDERRCODE_SHIFT); +} + +/*! @brief Returns whether the bus is idle. + * + * @param base FLEXSPI peripheral base address. + * @retval true Bus is idle. + * @retval false Bus is busy. + */ +static inline bool FLEXSPI_GetBusIdleStatus(FLEXSPI_Type *base) +{ + return (base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) && (base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK); +} +/*@}*/ + +/*! + * @name Bus Operations + * @{ + */ + +/*! @brief Update read sample clock source + * + * @param base FLEXSPI peripheral base address. + * @param clockSource clockSource of type #flexspi_read_sample_clock_t + */ +void FLEXSPI_UpdateRxSampleClock(FLEXSPI_Type *base, flexspi_read_sample_clock_t clockSource); + +/*! @brief Enables/disables the FLEXSPI IP command parallel mode. + * + * @param base FLEXSPI peripheral base address. + * @param enable True means enable parallel mode, false means disable parallel mode. + */ +static inline void FLEXSPI_EnableIPParallelMode(FLEXSPI_Type *base, bool enable) +{ + if (enable) + { + base->IPCR1 |= FLEXSPI_IPCR1_IPAREN_MASK; + } + else + { + base->IPCR1 &= ~FLEXSPI_IPCR1_IPAREN_MASK; + } +} + +/*! @brief Enables/disables the FLEXSPI AHB command parallel mode. + * + * @param base FLEXSPI peripheral base address. + * @param enable True means enable parallel mode, false means disable parallel mode. + */ +static inline void FLEXSPI_EnableAHBParallelMode(FLEXSPI_Type *base, bool enable) +{ + if (enable) + { + base->AHBCR |= FLEXSPI_AHBCR_APAREN_MASK; + } + else + { + base->AHBCR &= ~FLEXSPI_AHBCR_APAREN_MASK; + } +} + +/*! @brief Updates the LUT table. + * + * @param base FLEXSPI peripheral base address. + * @param index From which index start to update. It could be any index of the LUT table, which + * also allows user to update command content inside a command. Each command consists of up to + * 8 instructions and occupy 4*32-bit memory. + * @param cmd Command sequence array. + * @param count Number of sequences. + */ +void FLEXSPI_UpdateLUT(FLEXSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count); + +/*! + * @brief Writes data into FIFO. + * + * @param base FLEXSPI peripheral base address + * @param data The data bytes to send + * @param fifoIndex Destination fifo index. + */ +static inline void FLEXSPI_WriteData(FLEXSPI_Type *base, uint32_t data, uint8_t fifoIndex) +{ + base->TFDR[fifoIndex] = data; +} + +/*! + * @brief Receives data from data FIFO. + * + * @param base FLEXSPI peripheral base address + * @param fifoIndex Source fifo index. + * @return The data in the FIFO. + */ +static inline uint32_t FLEXSPI_ReadData(FLEXSPI_Type *base, uint8_t fifoIndex) +{ + return base->RFDR[fifoIndex]; +} + +/*! + * @brief Sends a buffer of data bytes using blocking method. + * @note This function blocks via polling until all bytes have been sent. + * @param base FLEXSPI peripheral base address + * @param buffer The data bytes to send + * @param size The number of data bytes to send + * @retval kStatus_Success write success without error + * @retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout + * @retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequencen error detected + * @retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected + */ +status_t FLEXSPI_WriteBlocking(FLEXSPI_Type *base, uint32_t *buffer, size_t size); + +/*! + * @brief Receives a buffer of data bytes using a blocking method. + * @note This function blocks via polling until all bytes have been sent. + * @param base FLEXSPI peripheral base address + * @param buffer The data bytes to send + * @param size The number of data bytes to receive + * @retval kStatus_Success read success without error + * @retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout + * @retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequencen error detected + * @retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected + */ +status_t FLEXSPI_ReadBlocking(FLEXSPI_Type *base, uint32_t *buffer, size_t size); + +/*! + * @brief Execute command to transfer a buffer data bytes using a blocking method. + * @param base FLEXSPI peripheral base address + * @param xfer pointer to the transfer structure. + * @retval kStatus_Success command transfer success without error + * @retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout + * @retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequencen error detected + * @retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected + */ +status_t FLEXSPI_TransferBlocking(FLEXSPI_Type *base, flexspi_transfer_t *xfer); +/*! @} */ + +/*! + * @name Transactional + * @{ + */ + +/*! + * @brief Initializes the FLEXSPI handle which is used in transactional functions. + * + * @param base FLEXSPI peripheral base address. + * @param handle pointer to flexspi_handle_t structure to store the transfer state. + * @param callback pointer to user callback function. + * @param userData user parameter passed to the callback function. + */ +void FLEXSPI_TransferCreateHandle(FLEXSPI_Type *base, + flexspi_handle_t *handle, + flexspi_transfer_callback_t callback, + void *userData); + +/*! + * @brief Performs a interrupt non-blocking transfer on the FLEXSPI bus. + * + * @note Calling the API returns immediately after transfer initiates. The user needs + * to call FLEXSPI_GetTransferCount to poll the transfer status to check whether + * the transfer is finished. If the return status is not kStatus_FLEXSPI_Busy, the transfer + * is finished. For FLEXSPI_Read, the dataSize should be multiple of rx watermark levle, or + * FLEXSPI could not read data properly. + * + * @param base FLEXSPI peripheral base address. + * @param handle pointer to flexspi_handle_t structure which stores the transfer state. + * @param xfer pointer to flexspi_transfer_t structure. + * @retval kStatus_Success Successfully start the data transmission. + * @retval kStatus_FLEXSPI_Busy Previous transmission still not finished. + */ +status_t FLEXSPI_TransferNonBlocking(FLEXSPI_Type *base, flexspi_handle_t *handle, flexspi_transfer_t *xfer); + +/*! + * @brief Gets the master transfer status during a interrupt non-blocking transfer. + * + * @param base FLEXSPI peripheral base address. + * @param handle pointer to flexspi_handle_t structure which stores the transfer state. + * @param count Number of bytes transferred so far by the non-blocking transaction. + * @retval kStatus_InvalidArgument count is Invalid. + * @retval kStatus_Success Successfully return the count. + */ +status_t FLEXSPI_TransferGetCount(FLEXSPI_Type *base, flexspi_handle_t *handle, size_t *count); + +/*! + * @brief Aborts an interrupt non-blocking transfer early. + * + * @note This API can be called at any time when an interrupt non-blocking transfer initiates + * to abort the transfer early. + * + * @param base FLEXSPI peripheral base address. + * @param handle pointer to flexspi_handle_t structure which stores the transfer state + */ +void FLEXSPI_TransferAbort(FLEXSPI_Type *base, flexspi_handle_t *handle); + +/*! + * @brief Master interrupt handler. + * + * @param base FLEXSPI peripheral base address. + * @param handle pointer to flexspi_handle_t structure. + */ +void FLEXSPI_TransferHandleIRQ(FLEXSPI_Type *base, flexspi_handle_t *handle); +/*! @} */ + +#if defined(__cplusplus) +} +#endif /*_cplusplus. */ +/*@}*/ + +#endif /* __FSL_FLEXSPI_H_ */ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_lpspi.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_lpspi.c new file mode 100755 index 000000000..82c1270ed --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_lpspi.c @@ -0,0 +1,2099 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 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, +}; + +/*! @brief Typedef for master interrupt handler. */ +typedef void (*lpspi_master_isr_t)(LPSPI_Type *base, lpspi_master_handle_t *handle); + +/*! @brief Typedef for slave interrupt handler. */ +typedef void (*lpspi_slave_isr_t)(LPSPI_Type *base, lpspi_slave_handle_t *handle); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Get instance number for LPSPI module. + * + * @param base LPSPI peripheral base address. + * @return Return the value of LPSPI instance. + */ +uint32_t LPSPI_GetInstance(LPSPI_Type *base); + +/*! + * @brief Configures the LPSPI peripheral chip select polarity. + * + * This function takes in the desired peripheral chip select (Pcs) and it's corresponding desired polarity and + * configures the Pcs signal to operate with the desired characteristic. + * + * @param base LPSPI peripheral address. + * @param pcs The particular peripheral chip select (parameter value is of type lpspi_which_pcs_t) for which we wish to + * apply the active high or active low characteristic. + * @param activeLowOrHigh The setting for either "active high, inactive low (0)" or "active low, inactive high(1)" of + * type lpspi_pcs_polarity_config_t. + */ +static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base, + lpspi_which_pcs_t pcs, + lpspi_pcs_polarity_config_t activeLowOrHigh); + +/*! + * @brief Combine the write data for 1 byte to 4 bytes. + * This is not a public API. + */ +static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint32_t bytesEachWrite, bool isByteSwap); + +/*! + * @brief Separate the read data for 1 byte to 4 bytes. + * This is not a public API. + */ +static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap); + +/*! + * @brief Master fill up the TX FIFO with data. + * This is not a public API. + */ +static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle); + +/*! + * @brief Master finish up a transfer. + * It would call back if there is callback function and set the state to idle. + * This is not a public API. + */ +static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle); + +/*! + * @brief Slave fill up the TX FIFO with data. + * This is not a public API. + */ +static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle); + +/*! + * @brief Slave finish up a transfer. + * It would call back if there is callback function and set the state to idle. + * This is not a public API. + */ +static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle); + +/*! + * @brief LPSPI common interrupt handler. + * + * @param handle pointer to s_lpspiHandle which stores the transfer state. + */ +static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* Defines constant value arrays for the baud rate pre-scalar and scalar divider values.*/ +static const uint8_t s_baudratePrescaler[] = {1, 2, 4, 8, 16, 32, 64, 128}; + +/*! @brief Pointers to lpspi bases for each instance. */ +static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS; + +/*! @brief Pointers to lpspi IRQ number for each instance. */ +static const IRQn_Type s_lpspiIRQ[] = LPSPI_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to lpspi clocks for each instance. */ +static const clock_ip_name_t s_lpspiClocks[] = LPSPI_CLOCKS; + +#if defined(LPSPI_PERIPH_CLOCKS) +static const clock_ip_name_t s_LpspiPeriphClocks[] = LPSPI_PERIPH_CLOCKS; +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointers to lpspi handles for each instance. */ +static void *s_lpspiHandle[ARRAY_SIZE(s_lpspiBases)] = {NULL}; + +/*! @brief Pointer to master IRQ handler for each instance. */ +static lpspi_master_isr_t s_lpspiMasterIsr; +/*! @brief Pointer to slave IRQ handler for each instance. */ +static lpspi_slave_isr_t s_lpspiSlaveIsr; +/* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/ +volatile uint8_t g_lpspiDummyData[ARRAY_SIZE(s_lpspiBases)] = {0}; +/********************************************************************************************************************** + * Code + *********************************************************************************************************************/ +uint32_t LPSPI_GetInstance(LPSPI_Type *base) +{ + uint8_t instance = 0; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_lpspiBases); instance++) + { + if (s_lpspiBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_lpspiBases)); + + return instance; +} + +/*! + * 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) +{ + uint32_t instance = LPSPI_GetInstance(base); + g_lpspiDummyData[instance] = dummyData; +} + +/*! + * 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) +{ + assert(masterConfig); + + uint32_t tcrPrescaleValue = 0; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPSPI_GetInstance(base); + /* Enable LPSPI clock */ + CLOCK_EnableClock(s_lpspiClocks[instance]); + +#if defined(LPSPI_PERIPH_CLOCKS) + CLOCK_EnableClock(s_LpspiPeriphClocks[instance]); +#endif + +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Set LPSPI to master */ + LPSPI_SetMasterSlaveMode(base, kLPSPI_Master); + + /* Set specific PCS to active high or low */ + LPSPI_SetOnePcsPolarity(base, masterConfig->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_OUTCFG(masterConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(masterConfig->pinCfg) | + LPSPI_CFGR1_NOSTALL(0); + + /* Set baudrate and delay times*/ + LPSPI_MasterSetBaudRate(base, masterConfig->baudRate, srcClock_Hz, &tcrPrescaleValue); + + /* Set default watermarks */ + LPSPI_SetFifoWatermarks(base, kLpspiDefaultTxWatermark, 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 - 1) | + LPSPI_TCR_PRESCALE(tcrPrescaleValue) | LPSPI_TCR_PCS(masterConfig->whichPcs); + + LPSPI_Enable(base, true); + + LPSPI_MasterSetDelayTimes(base, masterConfig->pcsToSckDelayInNanoSec, kLPSPI_PcsToSck, srcClock_Hz); + LPSPI_MasterSetDelayTimes(base, masterConfig->lastSckToPcsDelayInNanoSec, kLPSPI_LastSckToPcs, srcClock_Hz); + 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); + + /* Initializes the configure structure to zero. */ + 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 = 1000000000 / masterConfig->baudRate * 2; + masterConfig->lastSckToPcsDelayInNanoSec = 1000000000 / masterConfig->baudRate * 2; + masterConfig->betweenTransferDelayInNanoSec = 1000000000 / masterConfig->baudRate * 2; + + masterConfig->whichPcs = kLPSPI_Pcs0; + masterConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow; + + masterConfig->pinCfg = kLPSPI_SdiInSdoOut; + masterConfig->dataOutConfig = kLpspiDataOutRetained; +} + +/*! + * 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); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + + uint32_t instance = LPSPI_GetInstance(base); + /* Enable LPSPI clock */ + CLOCK_EnableClock(s_lpspiClocks[instance]); + +#if defined(LPSPI_PERIPH_CLOCKS) + 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, kLpspiDefaultTxWatermark, kLpspiDefaultRxWatermark); + + base->TCR = LPSPI_TCR_CPOL(slaveConfig->cpol) | LPSPI_TCR_CPHA(slaveConfig->cpha) | + LPSPI_TCR_LSBF(slaveConfig->direction) | LPSPI_TCR_FRAMESZ(slaveConfig->bitsPerFrame - 1); + + /* 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); + + /* Initializes the configure structure to zero. */ + 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 */ + CLOCK_DisableClock(s_lpspiClocks[instance]); + +#if defined(LPSPI_PERIPH_CLOCKS) + 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 & ~(1U << (LPSPI_CFGR1_PCSPOL_SHIFT + pcs)); + + /* Configure the PCS polarity bit according to the activeLowOrHigh setting */ + base->CFGR1 = cfgr1Value | ((uint32_t)activeLowOrHigh << (LPSPI_CFGR1_PCSPOL_SHIFT + 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); + + /* 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)) + { + return 0; + } + + 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 = 0; (prescaler < 8) && min_diff; prescaler++) + { + for (scaler = 0; (scaler < 256) && min_diff; scaler++) + { + 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. + */ + base->CCR = (base->CCR & ~LPSPI_CCR_SCKDIV_MASK) | LPSPI_CCR_SCKDIV(bestScaler); + + /* 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 */ + 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); + + 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 = 0; + } + + /* 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 initialDelayNanoSec; + } + + /* If min_diff = 0, the exit for loop */ + for (scaler = 0; (scaler < 256U) && min_diff; scaler++) + { + /* 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 *= (scaler + 1 + 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 = realDelay - 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 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); + + /* Zero the handle. */ + 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 transfer the transfer struct to be used. + * param bitPerFrame The bit size of one frame. + * param bytePerFrame The byte size of one frame. + * return Return true for right and false for wrong. + */ +bool LPSPI_CheckTransferArgument(lpspi_transfer_t *transfer, uint32_t bitsPerFrame, uint32_t bytesPerFrame) +{ + assert(transfer); + + /* If the transfer count is zero, then return immediately.*/ + if (transfer->dataSize == 0) + { + return false; + } + + /* If both send buffer and receive buffer is null */ + if ((!(transfer->txData)) && (!(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 <= 4) + { + if ((transfer->dataSize % bytesPerFrame) != 0) + { + return false; + } + } + else + { + if ((bytesPerFrame % 4U) != 0) + { + if (transfer->dataSize != bytesPerFrame) + { + return false; + } + } + else + { + if ((transfer->dataSize % bytesPerFrame) != 0) + { + return false; + } + } + } + + 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); + + uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1; + uint32_t bytesPerFrame = (bitsPerFrame + 7) / 8; + uint32_t temp = 0U; + uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)]; + + if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame)) + { + return kStatus_InvalidArgument; + } + + /* Check that LPSPI is not busy.*/ + if (LPSPI_GetStatusFlags(base) & kLPSPI_ModuleBusyFlag) + { + return kStatus_LPSPI_Busy; + } + + uint8_t *txData = transfer->txData; + uint8_t *rxData = transfer->rxData; + uint32_t txRemainingByteCount = transfer->dataSize; + uint32_t rxRemainingByteCount = transfer->dataSize; + + uint8_t bytesEachWrite; + uint8_t bytesEachRead; + + uint32_t readData = 0; + uint32_t wordToSend = + ((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*/ + uint32_t fifoSize = LPSPI_GetRxFifoSize(base); + + uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT; + + bool isPcsContinuous = (bool)(transfer->configFlags & kLPSPI_MasterPcsContinuous); + bool isRxMask = false; + bool isByteSwap = (bool)(transfer->configFlags & kLPSPI_MasterByteSwap); + + LPSPI_FlushFifo(base, true, true); + LPSPI_ClearStatusFlags(base, kLPSPI_AllStatusFlag); + + if (!rxData) + { + isRxMask = true; + } + + LPSPI_Enable(base, false); + base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); + /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */ + temp = base->CFGR1; + temp &= LPSPI_CFGR1_PINCFG_MASK; + if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) + { + if (!txData) + { + base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK; + } + /* The 3-wire mode can't send and receive data at the same time. */ + if ((txData) && (rxData)) + { + return kStatus_InvalidArgument; + } + } + LPSPI_Enable(base, true); + + base->TCR = + (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) | + LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_PCS(whichPcs); + + if (bytesPerFrame <= 4) + { + bytesEachWrite = bytesPerFrame; + bytesEachRead = bytesPerFrame; + } + else + { + bytesEachWrite = 4; + bytesEachRead = 4; + } + + /*Write the TX data until txRemainingByteCount is equal to 0 */ + while (txRemainingByteCount > 0) + { + if (txRemainingByteCount < bytesEachWrite) + { + bytesEachWrite = txRemainingByteCount; + } + + /*Wait until TX FIFO is not full*/ + while (LPSPI_GetTxFifoCount(base) == fifoSize) + { + } + + if (txData) + { + wordToSend = LPSPI_CombineWriteData(txData, bytesEachWrite, isByteSwap); + txData += bytesEachWrite; + } + + LPSPI_WriteData(base, wordToSend); + txRemainingByteCount -= bytesEachWrite; + + /*Check whether there is RX data in RX FIFO . Read out the RX data so that the RX FIFO would not overrun.*/ + if (rxData) + { + while (LPSPI_GetRxFifoCount(base)) + { + readData = LPSPI_ReadData(base); + if (rxRemainingByteCount < bytesEachRead) + { + bytesEachRead = rxRemainingByteCount; + } + + LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap); + rxData += bytesEachRead; + + rxRemainingByteCount -= bytesEachRead; + } + } + } + + /* After write all the data in TX FIFO , should write the TCR_CONTC to 0 to de-assert the PCS. Note that TCR + * register also use the TX FIFO. + */ + while ((LPSPI_GetTxFifoCount(base) == fifoSize)) + { + } + base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK)); + + /*Read out the RX data in FIFO*/ + if (rxData) + { + while (rxRemainingByteCount > 0) + { + while (LPSPI_GetRxFifoCount(base)) + { + readData = LPSPI_ReadData(base); + + if (rxRemainingByteCount < bytesEachRead) + { + bytesEachRead = rxRemainingByteCount; + } + + LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap); + rxData += bytesEachRead; + + rxRemainingByteCount -= bytesEachRead; + } + } + } + else + { + /* If no RX buffer, then transfer is not complete until transfer complete flag sets */ + while (!(LPSPI_GetStatusFlags(base) & kLPSPI_TransferCompleteFlag)) + { + } + } + + 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); + assert(transfer); + + uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1; + uint32_t bytesPerFrame = (bitsPerFrame + 7) / 8; + uint32_t temp = 0U; + uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)]; + + if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame)) + { + return kStatus_InvalidArgument; + } + + /* Check that we're not busy.*/ + if (handle->state == kLPSPI_Busy) + { + return kStatus_LPSPI_Busy; + } + + handle->state = kLPSPI_Busy; + + bool isRxMask = false; + + uint8_t txWatermark; + + uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT; + + handle->txData = transfer->txData; + handle->rxData = transfer->rxData; + handle->txRemainingByteCount = transfer->dataSize; + handle->rxRemainingByteCount = transfer->dataSize; + handle->totalByteCount = transfer->dataSize; + + handle->writeTcrInIsr = false; + + handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3) / 4); + 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 = (bool)(transfer->configFlags & kLPSPI_MasterPcsContinuous); + handle->isByteSwap = (bool)(transfer->configFlags & kLPSPI_MasterByteSwap); + + /*Set the RX and TX watermarks to reduce the ISR times.*/ + if (handle->fifoSize > 1) + { + txWatermark = 1; + handle->rxWatermark = handle->fifoSize - 2; + } + else + { + txWatermark = 0; + handle->rxWatermark = 0; + } + + LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark); + + LPSPI_Enable(base, false); + /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */ + base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); + /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */ + temp = base->CFGR1; + temp &= LPSPI_CFGR1_PINCFG_MASK; + if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) + { + if (!handle->txData) + { + base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK; + } + /* The 3-wire mode can't send and receive data at the same time. */ + if ((handle->txData) && (handle->rxData)) + { + return kStatus_InvalidArgument; + } + } + LPSPI_Enable(base, true); + + /*Flush FIFO , clear status , disable all the inerrupts.*/ + LPSPI_FlushFifo(base, true, true); + LPSPI_ClearStatusFlags(base, kLPSPI_AllStatusFlag); + LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable); + + /* If there is not rxData , can mask the receive data (receive data is not stored in receive FIFO). + * For master transfer , we'd better not masked the transmit data in TCR since the transfer flow is hard to + * controlled by software.*/ + if (handle->rxData == NULL) + { + isRxMask = true; + handle->rxRemainingByteCount = 0; + } + + base->TCR = + (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) | + LPSPI_TCR_CONT(handle->isPcsContinuous) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) | + LPSPI_TCR_PCS(whichPcs); + + /*Calculate the bytes for write/read the TX/RX register each time*/ + if (bytesPerFrame <= 4) + { + handle->bytesEachWrite = bytesPerFrame; + handle->bytesEachRead = bytesPerFrame; + } + else + { + handle->bytesEachWrite = 4; + handle->bytesEachRead = 4; + } + + /* 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. + */ + EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]); + + /*TCR is also shared the FIFO , so wait for TCR written.*/ + while (LPSPI_GetTxFifoCount(base) != 0) + { + } + /*Fill up the TX data in FIFO */ + 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) + { + /*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 ((handle->readRegRemainingTimes) <= handle->rxWatermark) + { + base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(handle->readRegRemainingTimes - 1); + } + + LPSPI_EnableInterrupts(base, kLPSPI_RxInterruptEnable); + } + else + { + LPSPI_EnableInterrupts(base, kLPSPI_TxInterruptEnable); + } + + return kStatus_Success; +} + +static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle) +{ + assert(handle); + + uint32_t wordToSend = 0; + + /* 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) < (handle->fifoSize)) && + (((handle->readRegRemainingTimes - handle->writeRegRemainingTimes) < handle->fifoSize) || + (handle->rxData == NULL))) + { + if (handle->txRemainingByteCount < handle->bytesEachWrite) + { + handle->bytesEachWrite = handle->txRemainingByteCount; + } + + if (handle->txData) + { + wordToSend = LPSPI_CombineWriteData(handle->txData, handle->bytesEachWrite, handle->isByteSwap); + handle->txData += handle->bytesEachWrite; + } + else + { + wordToSend = handle->txBuffIfNull; + } + + /*Write the word to TX register*/ + LPSPI_WriteData(base, wordToSend); + + /*Decrease the write TX register times.*/ + --handle->writeRegRemainingTimes; + + /*Decrease the remaining TX byte count.*/ + handle->txRemainingByteCount -= handle->bytesEachWrite; + + if (handle->txRemainingByteCount == 0) + { + /* 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) < (handle->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); + + /* Disable interrupt requests*/ + LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable); + + handle->state = kLPSPI_Idle; + + if (handle->callback) + { + 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); + + if (!count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (handle->state != kLPSPI_Busy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + size_t remainingByte; + + if (handle->rxData) + { + 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); + + /* Disable interrupt requests*/ + LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable); + + LPSPI_Reset(base); + + handle->state = 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); + + uint32_t readData; + + if (handle->rxData != NULL) + { + if (handle->rxRemainingByteCount) + { + /* 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, kLPSPI_RxInterruptEnable); + + while ((LPSPI_GetRxFifoCount(base)) && (handle->rxRemainingByteCount)) + { + /*Read out the data*/ + readData = LPSPI_ReadData(base); + + /*Decrease the read RX register times.*/ + --handle->readRegRemainingTimes; + + if (handle->rxRemainingByteCount < handle->bytesEachRead) + { + handle->bytesEachRead = handle->rxRemainingByteCount; + } + + LPSPI_SeparateReadData(handle->rxData, readData, handle->bytesEachRead, handle->isByteSwap); + handle->rxData += handle->bytesEachRead; + + /*Decrease the remaining RX byte count.*/ + handle->rxRemainingByteCount -= handle->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) + { + /* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */ + LPSPI_EnableInterrupts(base, 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 ((handle->readRegRemainingTimes) <= (handle->rxWatermark)) + { + base->FCR = + (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | + LPSPI_FCR_RXWATER((handle->readRegRemainingTimes > 1) ? (handle->readRegRemainingTimes - 1U) : (0U)); + } + } + + if (handle->txRemainingByteCount) + { + LPSPI_MasterTransferFillUpTxFifo(base, handle); + } + else + { + if ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize))) + { + if ((handle->isPcsContinuous) && (handle->writeTcrInIsr)) + { + base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK)); + handle->writeTcrInIsr = false; + } + } + } + + if ((handle->txRemainingByteCount == 0) && (handle->rxRemainingByteCount == 0) && (!handle->writeTcrInIsr)) + { + /* If no RX buffer, then transfer is not complete until transfer complete flag sets */ + if (handle->rxData == NULL) + { + if (LPSPI_GetStatusFlags(base) & kLPSPI_TransferCompleteFlag) + { + /* Complete the transfer and disable the interrupts */ + LPSPI_MasterTransferComplete(base, handle); + } + else + { + LPSPI_EnableInterrupts(base, kLPSPI_TransferCompleteInterruptEnable); + LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | 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); + + /* Zero the handle. */ + 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); + assert(transfer); + + uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1; + uint32_t bytesPerFrame = (bitsPerFrame + 7) / 8; + uint32_t temp = 0U; + + if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame)) + { + return kStatus_InvalidArgument; + } + + /* Check that we're not busy.*/ + if (handle->state == kLPSPI_Busy) + { + return kStatus_LPSPI_Busy; + } + handle->state = kLPSPI_Busy; + + bool isRxMask = false; + bool isTxMask = false; + + uint32_t whichPcs = (transfer->configFlags & LPSPI_SLAVE_PCS_MASK) >> LPSPI_SLAVE_PCS_SHIFT; + + 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 + 3) / 4); + handle->readRegRemainingTimes = handle->writeRegRemainingTimes; + + /*The TX and RX FIFO sizes are always the same*/ + handle->fifoSize = LPSPI_GetRxFifoSize(base); + + handle->isByteSwap = (bool)(transfer->configFlags & kLPSPI_SlaveByteSwap); + + /*Set the RX and TX watermarks to reduce the ISR times.*/ + uint8_t txWatermark; + if (handle->fifoSize > 1) + { + txWatermark = 1; + handle->rxWatermark = handle->fifoSize - 2; + } + else + { + txWatermark = 0; + handle->rxWatermark = 0; + } + LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark); + + /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */ + temp = base->CFGR1; + temp &= LPSPI_CFGR1_PINCFG_MASK; + if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) + { + if (!handle->txData) + { + LPSPI_Enable(base, false); + base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK; + LPSPI_Enable(base, true); + } + /* The 3-wire mode can't send and receive data at the same time. */ + if ((handle->txData) && (handle->rxData)) + { + return kStatus_InvalidArgument; + } + } + + /*Flush FIFO , clear status , disable all the inerrupts.*/ + LPSPI_FlushFifo(base, true, true); + LPSPI_ClearStatusFlags(base, kLPSPI_AllStatusFlag); + LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable); + + /*If there is not rxData , can mask the receive data (receive data is not stored in receive FIFO).*/ + if (handle->rxData == NULL) + { + isRxMask = true; + handle->rxRemainingByteCount = 0; + } + + /*If there is not txData , can mask the transmit data (no data is loaded from transmit FIFO and output pin + * is tristated). + */ + if (handle->txData == NULL) + { + isTxMask = true; + handle->txRemainingByteCount = 0; + } + + 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_CONT(0) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_TXMSK(isTxMask) | + LPSPI_TCR_PCS(whichPcs); + + /*Calculate the bytes for write/read the TX/RX register each time*/ + if (bytesPerFrame <= 4) + { + handle->bytesEachWrite = bytesPerFrame; + handle->bytesEachRead = bytesPerFrame; + } + else + { + handle->bytesEachWrite = 4; + handle->bytesEachRead = 4; + } + + /* 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. + */ + EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]); + + /*TCR is also shared the FIFO , so wait for TCR written.*/ + while (LPSPI_GetTxFifoCount(base) != 0) + { + } + + /*Fill up the TX data in FIFO */ + if (handle->txData) + { + 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) + { + /*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 ((handle->readRegRemainingTimes) <= handle->rxWatermark) + { + base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(handle->readRegRemainingTimes - 1); + } + + LPSPI_EnableInterrupts(base, kLPSPI_RxInterruptEnable); + } + else + { + LPSPI_EnableInterrupts(base, kLPSPI_TxInterruptEnable); + } + + if (handle->rxData) + { + /* RX FIFO overflow request enable */ + LPSPI_EnableInterrupts(base, kLPSPI_ReceiveErrorInterruptEnable); + } + if (handle->txData) + { + /* TX FIFO underflow request enable */ + LPSPI_EnableInterrupts(base, kLPSPI_TransmitErrorInterruptEnable); + } + + return kStatus_Success; +} + +static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle) +{ + assert(handle); + + uint32_t wordToSend = 0; + + while (LPSPI_GetTxFifoCount(base) < (handle->fifoSize)) + { + if (handle->txRemainingByteCount < handle->bytesEachWrite) + { + handle->bytesEachWrite = handle->txRemainingByteCount; + } + + wordToSend = LPSPI_CombineWriteData(handle->txData, handle->bytesEachWrite, handle->isByteSwap); + handle->txData += handle->bytesEachWrite; + + /*Decrease the remaining TX byte count.*/ + handle->txRemainingByteCount -= handle->bytesEachWrite; + + /*Write the word to TX register*/ + LPSPI_WriteData(base, wordToSend); + + if (handle->txRemainingByteCount == 0) + { + break; + } + } +} + +static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle) +{ + assert(handle); + + status_t status = 0; + + /* Disable interrupt requests*/ + LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable); + + if (handle->state == kLPSPI_Error) + { + status = kStatus_LPSPI_Error; + } + else + { + status = kStatus_Success; + } + + handle->state = kLPSPI_Idle; + + if (handle->callback) + { + 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); + + if (!count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (handle->state != kLPSPI_Busy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + size_t remainingByte; + + if (handle->rxData) + { + 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); + + /* Disable interrupt requests*/ + LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable); + + LPSPI_Reset(base); + + handle->state = kLPSPI_Idle; + handle->txRemainingByteCount = 0; + handle->rxRemainingByteCount = 0; +} + +/*! + * 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); + + uint32_t readData; /* variable to store word read from RX FIFO */ + uint32_t wordToSend; /* variable to store word to write to TX FIFO */ + + if (handle->rxData != NULL) + { + if (handle->rxRemainingByteCount > 0) + { + while (LPSPI_GetRxFifoCount(base)) + { + /*Read out the data*/ + readData = LPSPI_ReadData(base); + + /*Decrease the read RX register times.*/ + --handle->readRegRemainingTimes; + + if (handle->rxRemainingByteCount < handle->bytesEachRead) + { + handle->bytesEachRead = handle->rxRemainingByteCount; + } + + LPSPI_SeparateReadData(handle->rxData, readData, handle->bytesEachRead, handle->isByteSwap); + handle->rxData += handle->bytesEachRead; + + /*Decrease the remaining RX byte count.*/ + handle->rxRemainingByteCount -= handle->bytesEachRead; + + if ((handle->txRemainingByteCount > 0) && (handle->txData != NULL)) + { + if (handle->txRemainingByteCount < handle->bytesEachWrite) + { + handle->bytesEachWrite = handle->txRemainingByteCount; + } + + wordToSend = LPSPI_CombineWriteData(handle->txData, handle->bytesEachWrite, handle->isByteSwap); + handle->txData += handle->bytesEachWrite; + + /*Decrease the remaining TX byte count.*/ + handle->txRemainingByteCount -= handle->bytesEachWrite; + + /*Write the word to TX register*/ + LPSPI_WriteData(base, wordToSend); + } + + if (handle->rxRemainingByteCount == 0) + { + 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. + */ + if ((handle->readRegRemainingTimes) <= (handle->rxWatermark)) + { + base->FCR = + (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | + LPSPI_FCR_RXWATER((handle->readRegRemainingTimes > 1) ? (handle->readRegRemainingTimes - 1U) : (0U)); + } + } + else if ((handle->txRemainingByteCount) && (handle->txData != NULL)) + { + LPSPI_SlaveTransferFillUpTxFifo(base, handle); + } + else + { + __NOP(); + } + + if ((handle->txRemainingByteCount == 0) && (handle->rxRemainingByteCount == 0)) + { + /* 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) & kLPSPI_FrameCompleteFlag) && (LPSPI_GetTxFifoCount(base) == 0)) + { + /* Complete the transfer and disable the interrupts */ + LPSPI_SlaveTransferComplete(base, handle); + } + else + { + LPSPI_ClearStatusFlags(base, kLPSPI_FrameCompleteFlag); + LPSPI_EnableInterrupts(base, kLPSPI_FrameCompleteInterruptEnable); + LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | 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) & kLPSPI_TransmitErrorFlag) && (base->IER & LPSPI_IER_TEIE_MASK)) + { + LPSPI_ClearStatusFlags(base, kLPSPI_TransmitErrorFlag); + /* Change state to error and clear flag */ + if (handle->txData) + { + handle->state = kLPSPI_Error; + } + handle->errorCount++; + } + /* Catch rx fifo overflow conditions, service only if rx over flow interrupt enabled */ + if ((LPSPI_GetStatusFlags(base) & kLPSPI_ReceiveErrorFlag) && (base->IER & LPSPI_IER_REIE_MASK)) + { + LPSPI_ClearStatusFlags(base, kLPSPI_ReceiveErrorFlag); + /* Change state to error and clear flag */ + if (handle->txData) + { + handle->state = kLPSPI_Error; + } + handle->errorCount++; + } +} + +static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint32_t bytesEachWrite, bool isByteSwap) +{ + assert(txData); + + uint32_t wordToSend = 0; + + 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, uint32_t bytesEachRead, bool isByteSwap) +{ + assert(rxData); + + switch (bytesEachRead) + { + case 1: + *rxData = readData; + ++rxData; + break; + + case 2: + if (!isByteSwap) + { + *rxData = readData; + ++rxData; + *rxData = readData >> 8; + ++rxData; + } + else + { + *rxData = readData >> 8; + ++rxData; + *rxData = readData; + ++rxData; + } + break; + + case 3: + if (!isByteSwap) + { + *rxData = readData; + ++rxData; + *rxData = readData >> 8; + ++rxData; + *rxData = readData >> 16; + ++rxData; + } + else + { + *rxData = readData >> 16; + ++rxData; + *rxData = readData >> 8; + ++rxData; + *rxData = readData; + ++rxData; + } + break; + + case 4: + if (!isByteSwap) + { + *rxData = readData; + ++rxData; + *rxData = readData >> 8; + ++rxData; + *rxData = readData >> 16; + ++rxData; + *rxData = readData >> 24; + ++rxData; + } + else + { + *rxData = readData >> 24; + ++rxData; + *rxData = readData >> 16; + ++rxData; + *rxData = readData >> 8; + ++rxData; + *rxData = readData; + ++rxData; + } + break; + + default: + assert(false); + break; + } +} + +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); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +#if defined(LPSPI0) +void LPSPI0_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[0]); + LPSPI_CommonIRQHandler(LPSPI0, s_lpspiHandle[0]); +} +#endif + +#if defined(LPSPI1) +void LPSPI1_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[1]); + LPSPI_CommonIRQHandler(LPSPI1, s_lpspiHandle[1]); +} +#endif + +#if defined(LPSPI2) +void LPSPI2_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[2]); + LPSPI_CommonIRQHandler(LPSPI2, s_lpspiHandle[2]); +} +#endif + +#if defined(LPSPI3) +void LPSPI3_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[3]); + LPSPI_CommonIRQHandler(LPSPI3, s_lpspiHandle[3]); +} +#endif + +#if defined(LPSPI4) +void LPSPI4_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[4]); + LPSPI_CommonIRQHandler(LPSPI4, s_lpspiHandle[4]); +} +#endif + +#if defined(LPSPI5) +void LPSPI5_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[5]); + LPSPI_CommonIRQHandler(LPSPI5, s_lpspiHandle[5]); +} +#endif + +#if defined(DMA__LPSPI0) +void DMA_SPI0_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]); + LPSPI_CommonIRQHandler(DMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]); +} +#endif + +#if defined(DMA__LPSPI1) +void DMA_SPI1_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]); + LPSPI_CommonIRQHandler(DMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]); +} +#endif +#if defined(DMA__LPSPI2) +void DMA_SPI2_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]); + LPSPI_CommonIRQHandler(DMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]); +} +#endif + +#if defined(DMA__LPSPI3) +void DMA_SPI3_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]); + LPSPI_CommonIRQHandler(DMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]); +} +#endif + +#if defined(ADMA__LPSPI0) +void ADMA_SPI0_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]); + LPSPI_CommonIRQHandler(ADMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]); +} +#endif + +#if defined(ADMA__LPSPI1) +void ADMA_SPI1_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]); + LPSPI_CommonIRQHandler(ADMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]); +} +#endif +#if defined(ADMA__LPSPI2) +void ADMA_SPI2_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]); + LPSPI_CommonIRQHandler(ADMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]); +} +#endif + +#if defined(ADMA__LPSPI3) +void ADMA_SPI3_INT_DriverIRQHandler(void) +{ + assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]); + LPSPI_CommonIRQHandler(ADMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]); +} +#endif diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_lpspi.h b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_lpspi.h new file mode 100755 index 000000000..b3b9c0925 --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/fsl_lpspi.h @@ -0,0 +1,1109 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 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 2.0.3. */ +#define FSL_LPSPI_DRIVER_VERSION (MAKE_VERSION(2, 0, 3)) +/*@}*/ + +#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 Global variable for dummy data value setting. */ +extern volatile uint8_t g_lpspiDummyData[]; + +/*! @brief Status for the LPSPI driver.*/ +enum _lpspi_status +{ + 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. */ +}; + +/*! @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). */ +} 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 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 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 uint32_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 uint32_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 transfer the transfer struct to be used. + * @param bitPerFrame The bit size of one frame. + * @param bytePerFrame The byte size of one frame. + * @return Return true for right and false for wrong. + */ +bool LPSPI_CheckTransferArgument(lpspi_transfer_t *transfer, uint32_t bitsPerFrame, uint32_t bytesPerFrame); + +/*! + * @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 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 - 1); +} + +/*! + * @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 /*_cplusplus*/ + /*! + *@} + */ + +#endif /*_FSL_LPSPI_H_*/ diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/lpspi_interrupt.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/lpspi_interrupt.c new file mode 100755 index 000000000..cfc7b7ffc --- /dev/null +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/spi/lpspi_interrupt.c @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2013 - 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file lpspi_interrupt.c + * @brief Demo for SPI function + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022.1.18 + */ + +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "fsl_lpspi.h" +#include "board.h" + +#include "fsl_common.h" +#include "pin_mux.h" +#if ((defined FSL_FEATURE_SOC_INTMUX_COUNT) && (FSL_FEATURE_SOC_INTMUX_COUNT)) +#include "fsl_intmux.h" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* Master related */ +#define EXAMPLE_LPSPI_MASTER_BASEADDR (LPSPI3) +#define EXAMPLE_LPSPI_MASTER_IRQN (LPSPI3_IRQn) +#define EXAMPLE_LPSPI_MASTER_IRQHandler (LPSPI3_IRQHandler) + +#define EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT (kLPSPI_Pcs0) +#define EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER (kLPSPI_MasterPcs0) + +/* Slave related */ +#define EXAMPLE_LPSPI_SLAVE_BASEADDR (LPSPI1) +#define EXAMPLE_LPSPI_SLAVE_IRQN (LPSPI1_IRQn) +#define EXAMPLE_LPSPI_SLAVE_IRQHandler (LPSPI1_IRQHandler) + +#define EXAMPLE_LPSPI_SLAVE_PCS_FOR_INIT (kLPSPI_Pcs0) +#define EXAMPLE_LPSPI_SLAVE_PCS_FOR_TRANSFER (kLPSPI_SlavePcs0) + +/* Select USB1 PLL PFD0 (720 MHz) as lpspi clock source */ +#define EXAMPLE_LPSPI_CLOCK_SOURCE_SELECT (1U) +/* Clock divider for master lpspi clock source */ +#define EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER (7U) + +#define EXAMPLE_LPSPI_CLOCK_FREQ (CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER + 1U)) + +#define EXAMPLE_LPSPI_MASTER_CLOCK_FREQ EXAMPLE_LPSPI_CLOCK_FREQ +#define EXAMPLE_LPSPI_SLAVE_CLOCK_FREQ EXAMPLE_LPSPI_CLOCK_FREQ + +#define TRANSFER_SIZE (512U) /*! Transfer dataSize .*/ +#define TRANSFER_BAUDRATE (500000U) /*! Transfer baudrate - 500k */ + +#define spi_print KPrintf +#define spi_trace() KPrintf("lw: [%s][%d] passed!\n", __func__, __LINE__) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/* LPSPI user callback */ +void LPSPI_SlaveUserCallback(LPSPI_Type *base, lpspi_slave_handle_t *handle, status_t status, void *userData); +void LPSPI_MasterUserCallback(LPSPI_Type *base, lpspi_master_handle_t *handle, status_t status, void *userData); + +/******************************************************************************* + * Variables + ******************************************************************************/ +uint8_t masterRxData[TRANSFER_SIZE] = {0}; +uint8_t masterTxData[TRANSFER_SIZE] = {0}; +uint8_t slaveRxData[TRANSFER_SIZE] = {0}; +uint8_t slaveTxData[TRANSFER_SIZE] = {0}; + +volatile uint32_t slaveTxCount; +volatile uint32_t slaveRxCount; +uint8_t g_slaveRxWatermark; +uint8_t g_slaveFifoSize; + +volatile uint32_t masterTxCount; +volatile uint32_t masterRxCount; +uint8_t g_masterRxWatermark; +uint8_t g_masterFifoSize; + +volatile bool isSlaveTransferCompleted = false; +volatile bool isMasterTransferCompleted = false; + +/******************************************************************************* + * Code + ******************************************************************************/ +void LPSPI_SlaveUserCallback(LPSPI_Type *base, lpspi_slave_handle_t *handle, status_t status, void *userData) +{ + if (status == kStatus_Success) + { + spi_print("This is LPSPI slave transfer completed callback. \r\n"); + spi_print("It's a successful transfer. \r\n\r\n"); + } + else if (status == kStatus_LPSPI_Error) + { + spi_print("This is LPSPI slave transfer completed callback. \r\n"); + spi_print("Error occurred in this transfer. \r\n\r\n"); + } + else + { + __NOP(); + } + + isSlaveTransferCompleted = true; +} + +void LPSPI_MasterUserCallback(LPSPI_Type *base, lpspi_master_handle_t *handle, status_t status, void *userData) +{ + isMasterTransferCompleted = true; +} + +void EXAMPLE_LPSPI_SLAVE_IRQHandler(int vector, void *param) +{ + if (slaveRxCount < TRANSFER_SIZE) + { + while (LPSPI_GetRxFifoCount(EXAMPLE_LPSPI_SLAVE_BASEADDR)) + { + slaveRxData[slaveRxCount] = LPSPI_ReadData(EXAMPLE_LPSPI_SLAVE_BASEADDR); + slaveRxCount++; + + if (slaveTxCount < TRANSFER_SIZE) + { + LPSPI_WriteData(EXAMPLE_LPSPI_SLAVE_BASEADDR, slaveTxData[slaveTxCount]); + slaveTxCount++; + } + if (slaveRxCount == TRANSFER_SIZE) + { + break; + } + } + } + + /*Update rxWatermark. There isn't RX interrupt for the last datas if the RX count is not greater than rxWatermark.*/ + if ((TRANSFER_SIZE - slaveRxCount) <= g_slaveRxWatermark) + { + EXAMPLE_LPSPI_SLAVE_BASEADDR->FCR = + (EXAMPLE_LPSPI_SLAVE_BASEADDR->FCR & (~LPSPI_FCR_RXWATER_MASK)) | + LPSPI_FCR_RXWATER(((TRANSFER_SIZE - slaveRxCount) > 1) ? ((TRANSFER_SIZE - slaveRxCount) - 1U) : (0U)); + } + + /* Check if remaining receive byte count matches user request */ + if ((slaveRxCount == TRANSFER_SIZE) && (slaveTxCount == TRANSFER_SIZE)) + { + isSlaveTransferCompleted = true; + /* Disable interrupt requests */ + LPSPI_DisableInterrupts(EXAMPLE_LPSPI_SLAVE_BASEADDR, kLPSPI_RxInterruptEnable); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +DECLARE_HW_IRQ(EXAMPLE_LPSPI_SLAVE_IRQN, EXAMPLE_LPSPI_SLAVE_IRQHandler, NONE); + +void EXAMPLE_LPSPI_MASTER_IRQHandler(int vector, void *param) +{ + if (masterRxCount < TRANSFER_SIZE) + { + /* 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 EXAMPLE_LPSPI_MASTER_BASEADDRd on the LPSPI state after reading out the FIFO. + */ + LPSPI_DisableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_RxInterruptEnable); + + while (LPSPI_GetRxFifoCount(EXAMPLE_LPSPI_MASTER_BASEADDR)) + { + /*Read out the data*/ + masterRxData[masterRxCount] = LPSPI_ReadData(EXAMPLE_LPSPI_MASTER_BASEADDR); + + masterRxCount++; + + if (masterRxCount == TRANSFER_SIZE) + { + break; + } + } + + /* Re-enable the interrupts only if rxCount indicates there is more data to receive, + * else we may get a spurious interrupt. + * */ + if (masterRxCount < TRANSFER_SIZE) + { + /* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */ + LPSPI_EnableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_RxInterruptEnable); + } + } + + /*Update rxWatermark. There isn't RX interrupt for the last datas if the RX count is not greater than rxWatermark.*/ + if ((TRANSFER_SIZE - masterRxCount) <= g_masterRxWatermark) + { + EXAMPLE_LPSPI_MASTER_BASEADDR->FCR = + (EXAMPLE_LPSPI_MASTER_BASEADDR->FCR & (~LPSPI_FCR_RXWATER_MASK)) | + LPSPI_FCR_RXWATER(((TRANSFER_SIZE - masterRxCount) > 1) ? ((TRANSFER_SIZE - masterRxCount) - 1U) : (0U)); + } + + if (masterTxCount < TRANSFER_SIZE) + { + while ((LPSPI_GetTxFifoCount(EXAMPLE_LPSPI_MASTER_BASEADDR) < g_masterFifoSize) && + (masterTxCount - masterRxCount < g_masterFifoSize)) + { + /*Write the word to TX register*/ + LPSPI_WriteData(EXAMPLE_LPSPI_MASTER_BASEADDR, masterTxData[masterTxCount]); + ++masterTxCount; + + if (masterTxCount == TRANSFER_SIZE) + { + break; + } + } + } + + /* Check if we're done with this transfer.*/ + if ((masterTxCount == TRANSFER_SIZE) && (masterRxCount == TRANSFER_SIZE)) + { + isMasterTransferCompleted = true; + /* Complete the transfer and disable the interrupts */ + LPSPI_DisableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_AllInterruptEnable); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +DECLARE_HW_IRQ(EXAMPLE_LPSPI_MASTER_IRQN, EXAMPLE_LPSPI_MASTER_IRQHandler, NONE); + +void lpspi_config_init(void) +{ + lpspi_master_config_t masterConfig; + lpspi_slave_config_t slaveConfig; + + /*Master config*/ + masterConfig.baudRate = TRANSFER_BAUDRATE; + masterConfig.bitsPerFrame = 8; + masterConfig.cpol = kLPSPI_ClockPolarityActiveHigh; + masterConfig.cpha = kLPSPI_ClockPhaseFirstEdge; + masterConfig.direction = kLPSPI_MsbFirst; + + masterConfig.pcsToSckDelayInNanoSec = 1000000000 / masterConfig.baudRate; + masterConfig.lastSckToPcsDelayInNanoSec = 1000000000 / masterConfig.baudRate; + masterConfig.betweenTransferDelayInNanoSec = 1000000000 / masterConfig.baudRate; + + masterConfig.whichPcs = EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT; + masterConfig.pcsActiveHighOrLow = kLPSPI_PcsActiveLow; + + masterConfig.pinCfg = kLPSPI_SdiInSdoOut; + masterConfig.dataOutConfig = kLpspiDataOutRetained; + + LPSPI_MasterInit(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterConfig, EXAMPLE_LPSPI_MASTER_CLOCK_FREQ); + + /*Slave config*/ + slaveConfig.bitsPerFrame = masterConfig.bitsPerFrame; + slaveConfig.cpol = masterConfig.cpol; + slaveConfig.cpha = masterConfig.cpha; + slaveConfig.direction = masterConfig.direction; + + slaveConfig.whichPcs = EXAMPLE_LPSPI_SLAVE_PCS_FOR_INIT; + slaveConfig.pcsActiveHighOrLow = masterConfig.pcsActiveHighOrLow; + + slaveConfig.pinCfg = kLPSPI_SdiInSdoOut; + slaveConfig.dataOutConfig = kLpspiDataOutRetained; + + LPSPI_SlaveInit(EXAMPLE_LPSPI_SLAVE_BASEADDR, &slaveConfig); + +} + +/*! + * @brief Main function + */ +int test_spi(void) +{ + /*Set clock source for LPSPI*/ + CLOCK_SetMux(kCLOCK_LpspiMux, EXAMPLE_LPSPI_CLOCK_SOURCE_SELECT); + CLOCK_SetDiv(kCLOCK_LpspiDiv, EXAMPLE_LPSPI_CLOCK_SOURCE_DIVIDER); + + spi_print("LPSPI functional interrupt example start.\r\n"); + spi_print("This example use one lpspi instance as master and another as slave on one board.\r\n"); + spi_print("Master uses interrupt way and slave uses interrupt way.\r\n"); + spi_print( + "Note that some LPSPI instances interrupt is in INTMUX ," + "you should set the intmux when you porting this example accordingly \r\n"); + + spi_print("Please make sure you make the correct line connection. Basically, the connection is: \r\n"); + spi_print("LPSPI_master -- LPSPI_slave \r\n"); + spi_print(" CLK -- CLK \r\n"); + spi_print(" PCS -- PCS \r\n"); + spi_print(" SOUT -- SIN \r\n"); + spi_print(" SIN -- SOUT \r\n"); + + uint32_t errorCount; + uint32_t i; + uint32_t whichPcs; + uint8_t txWatermark; + + /*Set up the transfer data*/ + for (i = 0; i < TRANSFER_SIZE; i++) + { + masterTxData[i] = i % 256; + masterRxData[i] = 0; + + slaveTxData[i] = ~masterTxData[i]; + slaveRxData[i] = 0; + } + + lpspi_config_init(); + + /******************Set up slave first ******************/ + isSlaveTransferCompleted = false; + slaveTxCount = 0; + slaveRxCount = 0; + whichPcs = EXAMPLE_LPSPI_SLAVE_PCS_FOR_INIT; + + /*The TX and RX FIFO sizes are always the same*/ + g_slaveFifoSize = LPSPI_GetRxFifoSize(EXAMPLE_LPSPI_SLAVE_BASEADDR); + + /*Set the RX and TX watermarks to reduce the ISR times.*/ + if (g_slaveFifoSize > 1) + { + txWatermark = 1; + g_slaveRxWatermark = g_slaveFifoSize - 2; + } + else + { + txWatermark = 0; + g_slaveRxWatermark = 0; + } + + LPSPI_SetFifoWatermarks(EXAMPLE_LPSPI_SLAVE_BASEADDR, txWatermark, g_slaveRxWatermark); + + LPSPI_Enable(EXAMPLE_LPSPI_SLAVE_BASEADDR, false); + EXAMPLE_LPSPI_SLAVE_BASEADDR->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); + LPSPI_Enable(EXAMPLE_LPSPI_SLAVE_BASEADDR, true); + + /*Flush FIFO , clear status , disable all the interrupts.*/ + LPSPI_FlushFifo(EXAMPLE_LPSPI_SLAVE_BASEADDR, true, true); + LPSPI_ClearStatusFlags(EXAMPLE_LPSPI_SLAVE_BASEADDR, kLPSPI_AllStatusFlag); + LPSPI_DisableInterrupts(EXAMPLE_LPSPI_SLAVE_BASEADDR, kLPSPI_AllInterruptEnable); + + EXAMPLE_LPSPI_SLAVE_BASEADDR->TCR = + (EXAMPLE_LPSPI_SLAVE_BASEADDR->TCR & + ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) | + LPSPI_TCR_CONT(0) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(0) | LPSPI_TCR_TXMSK(0) | 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 interrupt in your application. + */ + EnableIRQ(EXAMPLE_LPSPI_SLAVE_IRQN); + + /*TCR is also shared the FIFO , so wait for TCR written.*/ + while (LPSPI_GetTxFifoCount(EXAMPLE_LPSPI_SLAVE_BASEADDR) != 0) + { + } + + spi_trace(); + + /*Fill up the TX data in FIFO */ + while (LPSPI_GetTxFifoCount(EXAMPLE_LPSPI_SLAVE_BASEADDR) < g_slaveFifoSize) + { + /*Write the word to TX register*/ + LPSPI_WriteData(EXAMPLE_LPSPI_SLAVE_BASEADDR, slaveTxData[slaveTxCount]); + ++slaveTxCount; + + if (slaveTxCount == TRANSFER_SIZE) + { + break; + } + } + spi_trace(); + + LPSPI_EnableInterrupts(EXAMPLE_LPSPI_SLAVE_BASEADDR, kLPSPI_RxInterruptEnable); + + /******************Set up master transfer******************/ + isMasterTransferCompleted = false; + masterTxCount = 0; + masterRxCount = 0; + whichPcs = EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT; + + /*The TX and RX FIFO sizes are always the same*/ + g_masterFifoSize = LPSPI_GetRxFifoSize(EXAMPLE_LPSPI_MASTER_BASEADDR); + + /*Set the RX and TX watermarks to reduce the ISR times.*/ + if (g_masterFifoSize > 1) + { + txWatermark = 1; + g_masterRxWatermark = g_masterFifoSize - 2; + } + else + { + txWatermark = 0; + g_masterRxWatermark = 0; + } + + LPSPI_SetFifoWatermarks(EXAMPLE_LPSPI_MASTER_BASEADDR, txWatermark, g_masterRxWatermark); + + LPSPI_Enable(EXAMPLE_LPSPI_MASTER_BASEADDR, false); + EXAMPLE_LPSPI_MASTER_BASEADDR->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); + LPSPI_Enable(EXAMPLE_LPSPI_MASTER_BASEADDR, true); + + /*Flush FIFO , clear status , disable all the inerrupts.*/ + LPSPI_FlushFifo(EXAMPLE_LPSPI_MASTER_BASEADDR, true, true); + LPSPI_ClearStatusFlags(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_AllStatusFlag); + LPSPI_DisableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_AllInterruptEnable); + + EXAMPLE_LPSPI_MASTER_BASEADDR->TCR = + (EXAMPLE_LPSPI_MASTER_BASEADDR->TCR & + ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) | + LPSPI_TCR_CONT(0) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(0) | LPSPI_TCR_TXMSK(0) | 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. + */ + EnableIRQ(EXAMPLE_LPSPI_MASTER_IRQN); + + /*TCR is also shared the FIFO , so wait for TCR written.*/ + while (LPSPI_GetTxFifoCount(EXAMPLE_LPSPI_MASTER_BASEADDR) != 0) + { + } + + spi_trace(); + + /*Fill up the TX data in FIFO */ + while ((LPSPI_GetTxFifoCount(EXAMPLE_LPSPI_MASTER_BASEADDR) < g_masterFifoSize) && + (masterTxCount - masterRxCount < g_masterFifoSize)) + { + /*Write the word to TX register*/ + LPSPI_WriteData(EXAMPLE_LPSPI_MASTER_BASEADDR, masterTxData[masterTxCount]); + ++masterTxCount; + + spi_trace(); + + if (masterTxCount == TRANSFER_SIZE) + { + break; + } + } + spi_trace(); + + LPSPI_EnableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_RxInterruptEnable); + + /******************Wait for master and slave transfer completed.******************/ + while ((!isSlaveTransferCompleted) || (!isMasterTransferCompleted)) + { + } + + spi_trace(); + + errorCount = 0; + for (i = 0; i < TRANSFER_SIZE; i++) + { + if (masterTxData[i] != slaveRxData[i]) + { + errorCount++; + } + + if (slaveTxData[i] != masterRxData[i]) + { + errorCount++; + } + } + if (errorCount == 0) + { + spi_print("\r\nLPSPI transfer all data matched! \r\n"); + } + else + { + spi_print("\r\nError occurred in LPSPI transfer ! \r\n"); + } + + LPSPI_Deinit(EXAMPLE_LPSPI_MASTER_BASEADDR); + LPSPI_Deinit(EXAMPLE_LPSPI_SLAVE_BASEADDR); + + spi_print("End of example. \r\n"); + + while (1) + { + } + spi_trace(); + +} + +SHELL_EXPORT_CMD (SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0), + spi, test_spi, SPI test ); + diff --git a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/uart/fsl_lpuart.c b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/uart/fsl_lpuart.c index 14c97f517..c4a8d0e99 100755 --- a/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/uart/fsl_lpuart.c +++ b/Ubiquitous/XiUOS/board/ok1052-c/third_party_driver/uart/fsl_lpuart.c @@ -6,18 +6,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (c) 2021 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - /** * @file fsl_lpuart.c * @brief fsl uart drivers diff --git a/Ubiquitous/XiUOS/kernel/include/user_api.h b/Ubiquitous/XiUOS/kernel/include/user_api.h index 48e9f8375..6171fbff3 100644 --- a/Ubiquitous/XiUOS/kernel/include/user_api.h +++ b/Ubiquitous/XiUOS/kernel/include/user_api.h @@ -50,11 +50,11 @@ int UserPrintInfo(unsigned long i); struct utask { - char name[NAME_NUM_MAX]; - void *func_entry; - void *func_param; - int32_t stack_size; - uint8_t prio; + char name[NAME_NUM_MAX]; + void *func_entry; + void *func_param; + int32_t stack_size; + uint8_t prio; }; typedef struct utask UtaskType; @@ -109,7 +109,7 @@ typedef int32 EventIdType; EventIdType UserEventCreate(uint8_t flag); void UserEventDelete(EventIdType event); x_err_t UserEventTrigger(EventIdType event, uint32_t set); -x_err_t UserEventProcess(EventIdType event, uint32_t set, uint8_t option, +x_err_t UserEventProcess(EventIdType event, uint32_t set, uint8_t option, int32_t wait_time, uint32_t *Recved); x_err_t UserEventReinit(EventIdType event); #endif @@ -162,7 +162,7 @@ int statfs(const char *path, struct statfs *buf); int Userprintf(const char *fmt, ...); -#define printf Userprintf +#define printf Userprintf #else @@ -172,11 +172,11 @@ int Userprintf(const char *fmt, ...); struct utask { - char name[NAME_NUM_MAX]; - void *func_entry; - void *func_param; - int32_t stack_size; - uint8_t prio; + char name[NAME_NUM_MAX]; + void *func_entry; + void *func_param; + int32_t stack_size; + uint8_t prio; }; typedef struct utask UtaskType; int32_t UserTaskCreate(UtaskType utask); diff --git a/Ubiquitous/XiUOS/kernel/kernel_test/test_i2c.c b/Ubiquitous/XiUOS/kernel/kernel_test/test_i2c.c index b67bdfd21..2a025feb4 100644 --- a/Ubiquitous/XiUOS/kernel/kernel_test/test_i2c.c +++ b/Ubiquitous/XiUOS/kernel/kernel_test/test_i2c.c @@ -13,7 +13,7 @@ /** * @file test_i2c.c * @brief support to test i2c function -* @version 1.0 +* @version 1.0 * @author AIIT XUOS Lab * @date 2021-04-24 */ @@ -24,15 +24,15 @@ /*********************************************************************************************************************************************************/ /* - * function:I2C device sample support reading temperature and humidity sensor data and printfing on the terminal - * shell cmd:i2c_HS3000_sample i2c1 - * shell cmd param:i2c device name,if null means default i2c device name + * function: I2C device sample support reading temperature and humidity sensor data and printfing on the terminal + * shell cmd: i2c_HS3000_sample i2c1 + * shell cmd param: i2c device name,if null means default i2c device name */ -#define HS_I2C_BUS_NAME I2C_BUS_NAME_1 /* I2C bus name */ -#define HS_I2C_DEV_NAME I2C_1_DEVICE_NAME_0/* I2C device name */ -#define HS_I2C_DRV_NAME I2C_DRV_NAME_1 /* I2C driver name */ -#define ADDR 0x44 /* slave address */ +#define HS_I2C_BUS_NAME I2C_BUS_NAME_1 /* I2C bus name */ +#define HS_I2C_DEV_NAME I2C_1_DEVICE_NAME_0 /* I2C device name */ +#define HS_I2C_DRV_NAME I2C_DRV_NAME_1 /* I2C driver name */ +#define ADDR 0x44 /* slave address */ static struct Bus *i2c_bus = NONE; /* I2C bus handle */ @@ -55,7 +55,7 @@ static x_err_t WriteReg(struct HardwareDev *dev) return EOK; } else{ - return -ERROR; + return -ERROR; } } @@ -89,7 +89,7 @@ static void ReadTempHumi(float *cur_temp, float *cur_humi) if(EOK != ret){ KPrintf("ReadTempHumi ReadRegs failed\n"); } - + *cur_humi = ((temp[0] <<8 | temp[1] )& 0x3fff ) * 100.0 / ( (1 << 14) - 1); /* humidity data */ *cur_temp = ((temp[2] << 8 | temp[3]) >> 2) * 165.0 /( (1 << 14) - 1) - 40.0; /* temperature data */ @@ -113,7 +113,7 @@ static void HS3000Init(const char *bus_name, const char *dev_name, const char * KPrintf("i2c match drv %s %p dev %s %p error\n", drv_name, i2c_bus->owner_driver, dev_name, i2c_bus->owner_haldev); } else{ - KPrintf("HS3000Init successfully!write %p read %p\n", + KPrintf("HS3000Init successfully!write %p read %p\n", i2c_bus->owner_haldev->dev_done->write, i2c_bus->owner_haldev->dev_done->read); } @@ -144,15 +144,15 @@ void TskHs300xTest() { memset(&g_hs300x_data, 0, sizeof(Hs300xDataType)); KPrintf("Tsk create successfully!\n"); - + while(1) { Hs300xRead(&g_hs300x_data); - KPrintf("HS300X:I2C humidity:%d.%d temperature:%d.%d\n", - g_hs300x_data.humi_high, - g_hs300x_data.humi_low, - g_hs300x_data.temp_high, + KPrintf("HS300X:I2C humidity:%d.%d temperature:%d.%d\n", + g_hs300x_data.humi_high, + g_hs300x_data.humi_low, + g_hs300x_data.temp_high, g_hs300x_data.temp_low); MdelayKTask(1000); @@ -167,12 +167,14 @@ void Hs300xI2cTest(void) MdelayKTask(1000); x_err_t flag; - int32 Tsk_hs300x = KTaskCreate("Tsk_hs300x", TskHs300xTest, NONE, 2048, 10); - flag = StartupKTask(Tsk_hs300x); + int32 Tsk_hs300x = KTaskCreate("Tsk_hs300x", TskHs300xTest, NONE, 2048, 10); + flag = StartupKTask(Tsk_hs300x); if (EOK != flag){ - KPrintf("Hs300xI2cTest StartupKTask failed!\n"); - return; - } + KPrintf("Hs300xI2cTest StartupKTask failed!\n"); + return; + } } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0), Hs300xI2cTest, Hs300xI2cTest, Test the HS300X using I2C); + + diff --git a/Ubiquitous/XiUOS/resources/Makefile b/Ubiquitous/XiUOS/resources/Makefile index d270dd528..2397f532d 100644 --- a/Ubiquitous/XiUOS/resources/Makefile +++ b/Ubiquitous/XiUOS/resources/Makefile @@ -1,10 +1,14 @@ SRC_DIR := -SRC_FILES += bus.c +SRC_FILES += bus.c ifeq ($(CONFIG_KERNEL_DEVICE),y) SRC_FILES += device.c endif +ifeq ($(CONFIG_RESOURCES_ADC),y) + SRC_DIR += adc +endif + ifeq ($(CONFIG_RESOURCES_CAN),y) SRC_DIR += can endif diff --git a/Ubiquitous/XiUOS/resources/adc/bus_adc.c b/Ubiquitous/XiUOS/resources/adc/bus_adc.c index c3231899d..de63fc144 100644 --- a/Ubiquitous/XiUOS/resources/adc/bus_adc.c +++ b/Ubiquitous/XiUOS/resources/adc/bus_adc.c @@ -13,7 +13,7 @@ /** * @file bus_adc.c * @brief register adc bus function using bus driver framework -* @version 1.1 +* @version 1.1 * @author AIIT XUOS Lab * @date 2021-12-28 */ @@ -21,6 +21,8 @@ #include #include +#if 0 + /*Register the ADC BUS*/ int AdcBusInit(struct AdcBus *adc_bus, const char *bus_name) { @@ -42,7 +44,7 @@ int AdcBusInit(struct AdcBus *adc_bus, const char *bus_name) return ret; } } else { - KPrintf("AdcBusInit BusRegister bus has been register state%u\n", adc_bus->bus.bus_state); + KPrintf("AdcBusInit BusRegister bus has been register state%u\n", adc_bus->bus.bus_state); } return ret; @@ -89,7 +91,7 @@ int AdcReleaseBus(struct AdcBus *adc_bus) int AdcDriverAttachToBus(const char *drv_name, const char *bus_name) { NULL_PARAM_CHECK(drv_name); - NULL_PARAM_CHECK(bus_name); + NULL_PARAM_CHECK(bus_name); x_err_t ret = EOK; @@ -120,3 +122,4 @@ int AdcDriverAttachToBus(const char *drv_name, const char *bus_name) return ret; } +#endif diff --git a/Ubiquitous/XiUOS/resources/adc/dev_adc.c b/Ubiquitous/XiUOS/resources/adc/dev_adc.c index 29fdfb49d..efe66d75f 100644 --- a/Ubiquitous/XiUOS/resources/adc/dev_adc.c +++ b/Ubiquitous/XiUOS/resources/adc/dev_adc.c @@ -13,7 +13,7 @@ /** * @file dev_adc.c * @brief register adc dev function using bus driver framework -* @version 1.1 +* @version 1.1 * @author AIIT XUOS Lab * @date 2021-12-28 */ @@ -29,16 +29,17 @@ static void AdcDeviceLinkInit() InitDoubleLinkList(&adcdev_linklist); } +#if 0 /*Find the register ADC device*/ HardwareDevType AdcDeviceFind(const char *dev_name, enum DevType dev_type) { NULL_PARAM_CHECK(dev_name); - + struct HardwareDev *device = NONE; DoubleLinklistType *node = NONE; DoubleLinklistType *head = &adcdev_linklist; - for (node = head->node_next; node != head; node = node->node_next) { + for (node = head->node_next; node != head; node = node->node_next) { device = SYS_DOUBLE_LINKLIST_ENTRY(node, struct HardwareDev, dev_link); if ((!strcmp(device->dev_name, dev_name)) && (dev_type == device->dev_type)) { return device; @@ -55,7 +56,7 @@ int AdcDeviceRegister(struct AdcHardwareDevice *adc_device, void *adc_param, con NULL_PARAM_CHECK(adc_device); NULL_PARAM_CHECK(device_name); - x_err_t ret = EOK; + x_err_t ret = EOK; static x_bool dev_link_flag = RET_FALSE; if (!dev_link_flag) { @@ -74,7 +75,7 @@ int AdcDeviceRegister(struct AdcHardwareDevice *adc_device, void *adc_param, con DoubleLinkListInsertNodeAfter(&adcdev_linklist, &(adc_device->haldev.dev_link)); } else { - KPrintf("AdcDeviceRegister device has been register state%u\n", adc_device->haldev.dev_state); + KPrintf("AdcDeviceRegister device has been register state%u\n", adc_device->haldev.dev_state); } return ret; @@ -85,7 +86,7 @@ int AdcDeviceAttachToBus(const char *dev_name, const char *bus_name) { NULL_PARAM_CHECK(dev_name); NULL_PARAM_CHECK(bus_name); - + x_err_t ret = EOK; struct Bus *bus; @@ -104,7 +105,7 @@ int AdcDeviceAttachToBus(const char *dev_name, const char *bus_name) KPrintf("AdcDeviceAttachToBus find adc device error!name %s\n", dev_name); return ERROR; } - + if (TYPE_ADC_DEV == device->dev_type) { ret = DeviceRegisterToBus(bus, device); @@ -117,3 +118,5 @@ int AdcDeviceAttachToBus(const char *dev_name, const char *bus_name) return EOK; } +#endif + diff --git a/Ubiquitous/XiUOS/resources/adc/drv_adc.c b/Ubiquitous/XiUOS/resources/adc/drv_adc.c index e96ebb411..d92a34179 100644 --- a/Ubiquitous/XiUOS/resources/adc/drv_adc.c +++ b/Ubiquitous/XiUOS/resources/adc/drv_adc.c @@ -13,7 +13,7 @@ /** * @file drv_adc.c * @brief register adc drv function using bus driver framework -* @version 1.1 +* @version 1.1 * @author AIIT XUOS Lab * @date 2021-12-28 */ @@ -29,11 +29,12 @@ static void AdcDrvLinkInit() InitDoubleLinkList(&adcdrv_linklist); } +#if 0 /*Find the regiter driver*/ DriverType AdcDriverFind(const char *drv_name, enum DriverType_e drv_type) { NULL_PARAM_CHECK(drv_name); - + struct Driver *driver = NONE; DoubleLinklistType *node = NONE; @@ -67,3 +68,4 @@ int AdcDriverRegister(struct Driver *driver) return ret; } +#endif diff --git a/Ubiquitous/XiUOS/resources/bus.c b/Ubiquitous/XiUOS/resources/bus.c index dc4b5ba6b..fc1df7002 100644 --- a/Ubiquitous/XiUOS/resources/bus.c +++ b/Ubiquitous/XiUOS/resources/bus.c @@ -12,8 +12,7 @@ /** * @file bus.c -* @brief 1、support bus driver framework;2、provide bus API。 -* @version 1.0 +* @brief Support bus driver framework provide bus API version 1.0 * @author AIIT XUOS Lab * @date 2021-04-24 */ @@ -71,7 +70,7 @@ static int BusMatchDrvDev(struct Driver *driver, struct HardwareDev *device) * @param dev - dev pointer * @param drv_name - drv name * @param configure_info - BusConfigureInfo pointer -* @return successful:EOK,failed:ERROR +* @return successful:EOK,failed:ERROR */ int DeviceObtainBus(struct Bus *bus, struct HardwareDev *dev, const char *drv_name, struct BusConfigureInfo *configure_info) { @@ -88,7 +87,7 @@ int DeviceObtainBus(struct Bus *bus, struct HardwareDev *dev, const char *drv_na if(bus->owner_haldev != dev) { struct Driver *drv = BusFindDriver(bus, drv_name); - + configure_info->configure_cmd = OPE_CFG; drv->configure(drv, configure_info); @@ -104,7 +103,7 @@ int DeviceObtainBus(struct Bus *bus, struct HardwareDev *dev, const char *drv_na /** * @Description: support to register bus pointer with linklist * @param bus - bus pointer -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ int BusRegister(struct Bus *bus) { @@ -125,7 +124,7 @@ int BusRegister(struct Bus *bus) /** * @Description: support to release bus pointer in linklist * @param bus - bus pointer -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ int BusRelease(struct Bus *bus) { @@ -147,7 +146,7 @@ int BusRelease(struct Bus *bus) /** * @Description: support to unregister bus pointer and delete its linklist node * @param bus - bus pointer -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ int BusUnregister(struct Bus *bus) { @@ -164,7 +163,7 @@ int BusUnregister(struct Bus *bus) * @Description: support to register driver pointer to bus pointer * @param bus - bus pointer * @param driver - driver pointer -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ int DriverRegisterToBus(struct Bus *bus, struct Driver *driver) { @@ -183,12 +182,12 @@ int DriverRegisterToBus(struct Bus *bus, struct Driver *driver) * @Description: support to register dev pointer to bus pointer * @param bus - bus pointer * @param device - device pointer -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ int DeviceRegisterToBus(struct Bus *bus, struct HardwareDev *device) { NULL_PARAM_CHECK(bus); - NULL_PARAM_CHECK(device); + NULL_PARAM_CHECK(device); device->owner_bus = bus; bus->haldev_cnt++; @@ -202,7 +201,7 @@ int DeviceRegisterToBus(struct Bus *bus, struct HardwareDev *device) * @Description: support to delete driver pointer from bus pointer * @param bus - bus pointer * @param driver - driver pointer -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ int DriverDeleteFromBus(struct Bus *bus, struct Driver *driver) { @@ -222,12 +221,12 @@ int DriverDeleteFromBus(struct Bus *bus, struct Driver *driver) * @Description: support to delete dev pointer from bus pointer * @param bus - bus pointer * @param device - device pointer -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ int DeviceDeleteFromBus(struct Bus *bus, struct HardwareDev *device) { NULL_PARAM_CHECK(bus); - NULL_PARAM_CHECK(device); + NULL_PARAM_CHECK(device); bus->haldev_cnt--; @@ -241,7 +240,7 @@ int DeviceDeleteFromBus(struct Bus *bus, struct HardwareDev *device) /** * @Description: support to find bus pointer by bus name * @param bus_name - bus name -* @return successful:bus pointer,failed:NONE +* @return successful:bus pointer,failed:NONE */ BusType BusFind(const char *bus_name) { @@ -266,7 +265,7 @@ BusType BusFind(const char *bus_name) * @Description: support to find driver pointer of certain bus by driver name * @param bus - bus pointer * @param driver_name - driver name -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ DriverType BusFindDriver(struct Bus *bus, const char *driver_name) { @@ -292,7 +291,7 @@ DriverType BusFindDriver(struct Bus *bus, const char *driver_name) * @Description: support to find device pointer of certain bus by device name * @param bus - bus pointer * @param device_name - device name -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ HardwareDevType BusFindDevice(struct Bus *bus, const char *device_name) { @@ -319,7 +318,7 @@ HardwareDevType BusFindDevice(struct Bus *bus, const char *device_name) * @Description: support to set dev receive function callback * @param dev - dev pointer * @param dev_recv_callback - callback function -* @return successful:EOK,failed:ERROR +* @return successful:EOK,failed:ERROR */ uint32 BusDevRecvCallback(struct HardwareDev *dev, int (*dev_recv_callback) (void *dev, x_size_t length)) { @@ -333,7 +332,7 @@ uint32 BusDevRecvCallback(struct HardwareDev *dev, int (*dev_recv_callback) (voi /** * @Description: support to open dev * @param dev - dev pointer -* @return successful:EOK,failed:ERROR +* @return successful:EOK,failed:ERROR */ uint32 BusDevOpen(struct HardwareDev *dev) { @@ -355,7 +354,7 @@ uint32 BusDevOpen(struct HardwareDev *dev) /** * @Description: support to close dev * @param dev - dev pointer -* @return successful:EOK,failed:ERROR +* @return successful:EOK,failed:ERROR */ uint32 BusDevClose(struct HardwareDev *dev) { @@ -378,12 +377,12 @@ uint32 BusDevClose(struct HardwareDev *dev) * @Description: support to write data to dev * @param dev - dev pointer * @param write_param - BusBlockWriteParam -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ uint32 BusDevWriteData(struct HardwareDev *dev, struct BusBlockWriteParam *write_param) { NULL_PARAM_CHECK(dev); - + if (dev->dev_done->write) { return dev->dev_done->write(dev, write_param); } @@ -395,12 +394,12 @@ uint32 BusDevWriteData(struct HardwareDev *dev, struct BusBlockWriteParam *write * @Description: support to read data from dev * @param dev - dev pointer * @param read_param - BusBlockReadParam -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ uint32 BusDevReadData(struct HardwareDev *dev, struct BusBlockReadParam *read_param) { NULL_PARAM_CHECK(dev); - + if (dev->dev_done->read) { return dev->dev_done->read(dev, read_param); } @@ -412,7 +411,7 @@ uint32 BusDevReadData(struct HardwareDev *dev, struct BusBlockReadParam *read_pa * @Description: support to configure drv, include OPE_CFG and OPE_INT * @param drv - drv pointer * @param configure_info - BusConfigureInfo -* @return successful:EOK,failed:NONE +* @return successful:EOK,failed:NONE */ uint32 BusDrvConfigure(struct Driver *drv, struct BusConfigureInfo *configure_info) { @@ -430,4 +429,4 @@ uint32 BusDrvConfigure(struct Driver *drv, struct BusConfigureInfo *configure_in } return ret; -} +} diff --git a/Ubiquitous/XiUOS/resources/ethernet/LwIP/arch/sys_arch.c b/Ubiquitous/XiUOS/resources/ethernet/LwIP/arch/sys_arch.c index 388263fcb..9075d6ea9 100644 --- a/Ubiquitous/XiUOS/resources/ethernet/LwIP/arch/sys_arch.c +++ b/Ubiquitous/XiUOS/resources/ethernet/LwIP/arch/sys_arch.c @@ -29,17 +29,6 @@ * Author: Simon Goldschmidt * */ -/* -* Copyright (c) 2020 AIIT XUOS Lab -* XiUOS is licensed under Mulan PSL v2. -* You can use this software according to the terms and conditions of the Mulan PSL v2. -* You may obtain a copy of Mulan PSL v2 at: -* http://license.coscl.org.cn/MulanPSL2 -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -* See the Mulan PSL v2 for more details. -*/ /** * @file sys_arch.c @@ -48,6 +37,7 @@ * @author AIIT XUOS Lab * @date 2021-05-29 */ + #include "debug.h" #include @@ -79,7 +69,6 @@ #include "board.h" #include "ethernet.h" #include "enet_ethernetif.h" -#include char lwip_ipaddr[] = {192, 168, 250, 253}; char lwip_netmask[] = {255, 255, 255, 0}; @@ -463,9 +452,10 @@ void lwip_input_thread(void *param) void lwip_config_input(struct netif *net) { - pthread_t th_id = 0; + sys_thread_t th_id = 0; - th_id = sys_thread_new("eth_input", lwip_input_thread, net, 4096, 15); + th_id = sys_thread_new("eth_input", lwip_input_thread, net, LWIP_TASK_STACK_SIZE, + LWIP_DEMO_TASK_PRIO); if (th_id >= 0) { lw_print("%s %d successfully!\n", __func__, th_id); diff --git a/Ubiquitous/XiUOS/resources/ethernet/LwIP/arch/sys_arch.h b/Ubiquitous/XiUOS/resources/ethernet/LwIP/arch/sys_arch.h index ab5a66b2a..77368791d 100644 --- a/Ubiquitous/XiUOS/resources/ethernet/LwIP/arch/sys_arch.h +++ b/Ubiquitous/XiUOS/resources/ethernet/LwIP/arch/sys_arch.h @@ -29,17 +29,6 @@ * Author: Simon Goldschmidt * */ -/* -* Copyright (c) 2020 AIIT XUOS Lab -* XiUOS is licensed under Mulan PSL v2. -* You can use this software according to the terms and conditions of the Mulan PSL v2. -* You may obtain a copy of Mulan PSL v2 at: -* http://license.coscl.org.cn/MulanPSL2 -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -* See the Mulan PSL v2 for more details. -*/ /** * @file sys_arch.h diff --git a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_config_demo.c b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_config_demo.c index 8a5c13be9..b8fd680e5 100755 --- a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_config_demo.c +++ b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_config_demo.c @@ -1,12 +1,3 @@ -/* - * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2019 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - /* * Copyright (c) 2021 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. @@ -79,8 +70,8 @@ void lwip_setip_thread(int argc, char *argv[]) pthread_t th_id; pthread_attr_t attr; - attr.schedparam.sched_priority = 15; - attr.stacksize = 4096; + attr.schedparam.sched_priority = LWIP_DEMO_TASK_PRIO; + attr.stacksize = LWIP_TASK_STACK_SIZE; if(argc >= 4) { diff --git a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_demo.h b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_demo.h index 99e273aa1..f1077106a 100755 --- a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_demo.h +++ b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_demo.h @@ -1,3 +1,23 @@ +/* + * Copyright (c) 2021 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file lwip_demo.h + * @brief lwip demo header + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022.1.18 + */ + #ifndef __LWIP_DEMO_H__ #define __LWIP_DEMO_H__ diff --git a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_dhcp_demo.c b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_dhcp_demo.c index 6cf60699e..956747d93 100755 --- a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_dhcp_demo.c +++ b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_dhcp_demo.c @@ -7,6 +7,14 @@ * SPDX-License-Identifier: BSD-3-Clause */ +/** + * @file lwip_dhcp_demo.c + * @brief Demo for DHCP function + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.12.15 + */ + /******************************************************************************* * Includes ******************************************************************************/ diff --git a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_ping_demo.c b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_ping_demo.c index a0c6807bb..f84053730 100755 --- a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_ping_demo.c +++ b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_ping_demo.c @@ -1,12 +1,3 @@ -/* - * Copyright (c) 2016, Freescale Semiconductor, Inc. - * Copyright 2016-2019 NXP - * All rights reserved. - * - * - * SPDX-License-Identifier: BSD-3-Clause - */ - /* * Copyright (c) 2021 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. @@ -27,7 +18,6 @@ * @date 2021.12.15 */ - /******************************************************************************* * Includes ******************************************************************************/ @@ -46,7 +36,6 @@ #include "pin_mux.h" #include "clock_config.h" -#include #include #include "connect_ethernet.h" @@ -71,14 +60,6 @@ ip4_addr_t ping_addr; * Code ******************************************************************************/ -static void *lwip_ping_test(void *param) -{ - IP4_ADDR(&ping_addr, lwip_gwaddr[0], lwip_gwaddr[1], lwip_gwaddr[2], lwip_gwaddr[3]); - ETH_BSP_Config(); - lwip_config_net(lwip_ipaddr, lwip_netmask, lwip_gwaddr); - ping_init(&ping_addr); -} - void lwip_ping_thread(int argc, char *argv[]) { int result = 0; diff --git a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_tcp_demo.c b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_tcp_demo.c index baebfbbcb..afc1aa67a 100755 --- a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_tcp_demo.c +++ b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_tcp_demo.c @@ -17,7 +17,6 @@ * @author AIIT XUOS Lab * @date 2021-05-29 */ -#include #include #include "board.h" #include "sys_arch.h" diff --git a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_udp_demo.c b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_udp_demo.c index 5dd19c5c3..5eb214771 100755 --- a/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_udp_demo.c +++ b/Ubiquitous/XiUOS/resources/ethernet/cmd_lwip/lwip_udp_demo.c @@ -11,13 +11,12 @@ */ /** -* @file tcp_echo_socket_demo.c +* @file lwip_udp_demo.c * @brief One UDP demo based on LwIP * @version 1.0 * @author AIIT XUOS Lab * @date 2021-05-29 */ -#include #include #include "board.h" #include "sys_arch.h" @@ -95,8 +94,7 @@ __exit: void *lwip_udp_send_run(int argc, char *argv[]) { int result = 0; - pthread_t th_id; - pthread_attr_t attr; + sys_thread_t th_id; memset(udp_send_msg, 0, sizeof(udp_send_msg)); @@ -118,7 +116,7 @@ void *lwip_udp_send_run(int argc, char *argv[]) ETH_BSP_Config(); lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); - sys_thread_new("udp socket send", lwip_udp_send, NULL, 4096, 25); + sys_thread_new("udp socket send", lwip_udp_send, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO); } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), diff --git a/Ubiquitous/XiUOS/resources/include/dev_adc.h b/Ubiquitous/XiUOS/resources/include/dev_adc.h index 23633d605..e1d2b5162 100644 --- a/Ubiquitous/XiUOS/resources/include/dev_adc.h +++ b/Ubiquitous/XiUOS/resources/include/dev_adc.h @@ -13,7 +13,7 @@ /** * @file dev_adc.h * @brief define adc dev function using bus driver framework -* @version 1.1 +* @version 1.1 * @author AIIT XUOS Lab * @date 2021-12-28 */ diff --git a/Ubiquitous/XiUOS/resources/include/flash_spi.h b/Ubiquitous/XiUOS/resources/include/flash_spi.h index 3ea08e5ac..f41d40d25 100644 --- a/Ubiquitous/XiUOS/resources/include/flash_spi.h +++ b/Ubiquitous/XiUOS/resources/include/flash_spi.h @@ -13,7 +13,7 @@ /** * @file flash_spi.h * @brief define spi-flash dev function using bus driver framework -* @version 1.0 +* @version 1.0 * @author AIIT XUOS Lab * @date 2021-04-24 */ diff --git a/Ubiquitous/XiUOS/resources/spi/dev_spi.c b/Ubiquitous/XiUOS/resources/spi/dev_spi.c index b2cc0f0ae..8e16da4c5 100644 --- a/Ubiquitous/XiUOS/resources/spi/dev_spi.c +++ b/Ubiquitous/XiUOS/resources/spi/dev_spi.c @@ -13,7 +13,7 @@ /** * @file dev_spi.c * @brief register spi dev function using bus driver framework -* @version 1.0 +* @version 1.0 * @author AIIT XUOS Lab * @date 2021-04-24 */ @@ -36,7 +36,7 @@ static uint32 SpiDeviceOpen(void *dev) SpiDevConfigureCs(dev, 1, 0); return EOK; -} +} static uint32 SpiDeviceClose(void *dev) { @@ -45,7 +45,7 @@ static uint32 SpiDeviceClose(void *dev) SpiDevConfigureCs(dev, 0, 1); return EOK; -} +} static uint32 SpiDeviceWrite(void *dev, struct BusBlockWriteParam *write_param) { @@ -120,7 +120,7 @@ static const struct HalDevDone dev_done = HardwareDevType SpiDeviceFind(const char *dev_name, enum DevType dev_type) { NULL_PARAM_CHECK(dev_name); - + struct HardwareDev *device = NONE; DoubleLinklistType *node = NONE; @@ -142,7 +142,7 @@ int SpiDeviceRegister(struct SpiHardwareDevice *spi_device, void *spi_param, con NULL_PARAM_CHECK(spi_device); NULL_PARAM_CHECK(device_name); - x_err_t ret = EOK; + x_err_t ret = EOK; static x_bool dev_link_flag = RET_FALSE; if (!dev_link_flag) { @@ -164,7 +164,7 @@ int SpiDeviceRegister(struct SpiHardwareDevice *spi_device, void *spi_param, con DoubleLinkListInsertNodeAfter(&spidev_linklist, &(spi_device->haldev.dev_link)); } else { - KPrintf("SpiDeviceRegister device has been register state%u\n", spi_device->haldev.dev_state); + KPrintf("SpiDeviceRegister device has been register state%u\n", spi_device->haldev.dev_state); } return ret; @@ -174,7 +174,7 @@ int SpiDeviceAttachToBus(const char *dev_name, const char *bus_name) { NULL_PARAM_CHECK(dev_name); NULL_PARAM_CHECK(bus_name); - + x_err_t ret = EOK; struct Bus *bus; @@ -185,7 +185,7 @@ int SpiDeviceAttachToBus(const char *dev_name, const char *bus_name) KPrintf("SpiDeviceAttachToBus find spi bus error!name %s\n", bus_name); return ERROR; } - + if (TYPE_SPI_BUS == bus->bus_type) { device = SpiDeviceFind(dev_name, TYPE_SPI_DEV); if (NONE == device) {