CSK6 可用 GPIO 引脚多达 33 个,每个引脚均支持下列功能配置:
输入
上拉输出
下拉输出
推挽输出
中断
除作为通用 I/O 外,CSK6 每个引脚均可灵活地配置为外设引脚功能,I/O 和引脚功能的映射关系请联系聆思获取。这里,仅对默认功能非通用 I/O 的引脚进行简要说明:
引脚序号 | 引脚名称 | 默认功能 |
---|---|---|
1 | SWDCLK | AP 调试接口 |
2 | SWDIO | AP 调试接口 |
11 | GPIOA_10 | CP 调试接口 |
12 | GPIOA_11 | CP 调试接口 |
13 | GPIOA_12 | CP 调试接口 |
14 | GPIOA_13 | CP 调试接口 |
15 | GPIOA_14 | CP 调试接口 |
枚举值 | 说明 |
---|---|
CSK_GPIO_DIR_INPUT | 输入 |
CSK_GPIO_DIR_OUTPUT | 输出 |
枚举值 | 说明 |
---|---|
CSK_GPIO_SET_INTR_LOW_LEVEL | 低电平触发 |
CSK_GPIO_SET_INTR_HIGH_LEVEL | 高电平触发 |
CSK_GPIO_SET_INTR_NEGATIVE_EDGE | 下降沿触发 |
CSK_GPIO_SET_INTR_POSITIVE_EDGE | 上升沿触发 |
CSK_GPIO_SET_INTR_DUAL_EDGE | 上升/下降沿均触发 |
void* GPIOA(void);
void* GPIOB(void);
void*
, 指向 GPIO 端口实例的句柄int32_t GPIO_Initialize(void *res, CSK_GPIO_SignalEvent_t cb_event, void* workspace);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void* | GPIO实例句柄 |
cb_event | CSK_GPIO_SignalEvent_t | 事件回调函数 |
workspace | void* | 传入 NULL 即可 |
int32_t GPIO_Uninitialize(void *res);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void* | GPIO实例句柄 |
int32_t GPIO_PowerControl(void* res, CSK_POWER_STATE state);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void* | GPIO实例句柄 |
state | CSK_POWER_STATE | 使能状态 CSK_POWER_OFF:失能状态 CSK_POWER_LOW:低功耗状态 CSK_POWER_FULL:全功能状态 |
int32_t GPIO_Control(void* res, uint32_t control, uint32_t arg);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void* | GPIO实例句柄 |
control | uint32_t | 配置参数 |
arg | uint32_t | 可选参数 |
int32_t GPIO_PinWrite(void* res, uint32_t pin_mask, uint32_t val);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void* | GPIO实例句柄 |
pin_mask | uint32_t | 引脚 MASK |
val | uint32_t | 引脚电平状态 |
int32_t GPIO_PinRead(void* res, uint32_t pin_mask);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void* | GPIO实例句柄 |
pin_mask | uint32_t | 引脚MASK |
int32_t GPIO_SetDir(void* res, uint32_t pin_mask, uint32_t dir);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void* | GPIO实例句柄 |
pin_mask | uint32_t | 引脚MASK |
dir | uint32_t | 输入/输出配置 |
示例基于 CSK6012-NanoKit V1 硬件进行演示。
程序片段启动 blinky 任务,控制连接到 GPIOA5 的 Led 灯间隔 200ms 进行闪烁。
#include "appinc.h"
void blinky_task(void *arg)
{
uint8_t pin_state = 0;
void *handle = GPIOA();
GPIO_Initialize(handle, NULL, NULL);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 5, 0);
GPIO_SetDir(handle, CSK_GPIO_PIN5, CSK_GPIO_DIR_OUTPUT);
GPIO_PinWrite(handle, CSK_GPIO_PIN5, pin_state);
while (true) {
LOGI("blinky: %d", pin_state);
vTaskDelay(pdMS_TO_TICKS(200));
pin_state = !pin_state;
GPIO_PinWrite(handle, CSK_GPIO_PIN5, pin_state);
}
vTaskDelete(NULL);
}
int main(void)
{
xTaskCreate(blinky_task, "test.blinky", DEF_TASK_STACK, NULL, DEF_TASK_PRIO, NULL);
vTaskStartScheduler();
return 0;
}
程序片段启动 intrrupt 任务,通过连接到 GPIOB5 的微动按键控制连接到 GPIOA5 的 Led 灯状态,按键按下 Led 灯点亮,按键松开 Led 灯熄灭。
#include "appinc.h"
void *hdl_a = NULL;
void *hdl_b = NULL;
uint8_t led_state = 0;
void gpio_drv_event(uint32_t event, void *ws)
{
// LOGI("event: %#x", event);
if (event & CSK_GPIO_PIN5)
led_state = GPIO_PinRead(hdl_b, CSK_GPIO_PIN5);
}
void testcase_interrupt_task(void *arg)
{
hdl_a = GPIOA();
GPIO_Initialize(hdl_a, NULL, NULL);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 5, CSK_IOMUX_FUNC_DEFAULT);
GPIO_SetDir(hdl_a, CSK_GPIO_PIN5, CSK_GPIO_DIR_OUTPUT);
GPIO_PinWrite(hdl_a, CSK_GPIO_PIN5, 1);
hdl_b = GPIOB();
GPIO_Initialize(hdl_b, gpio_drv_event, NULL);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_B, 5, CSK_IOMUX_FUNC_DEFAULT);
IOMuxManager_ModeConfigure(CSK_IOMUX_PAD_B, 5, HAL_IOMUX_PULLUP_MODE);
GPIO_SetDir(hdl_b, CSK_GPIO_PIN5, CSK_GPIO_DIR_INPUT);
GPIO_Control(hdl_b,
CSK_GPIO_INTR_ENABLE | CSK_GPIO_SET_INTR_DUAL_EDGE | CSK_GPIO_DEBOUNCE_ENABLE, CSK_GPIO_PIN5);
// GPIO_Control(hdl_b, CSK_GPIO_DEBOUNCE_SCALE, 0xff);
while (true) {
GPIO_PinWrite(hdl_a, CSK_GPIO_PIN5, led_state);
vTaskDelay(pdMS_TO_TICKS(10));
}
vTaskDelete(NULL);
}
int main(void)
{
NVIC_GetPriorityGrouping();
NVIC_SetPriorityGrouping(4UL);
NVIC_GetPriorityGrouping();
xTaskCreate(intrrupt_task, "test.intr", DEF_TASK_STACK, NULL, DEF_TASK_PRIO, NULL);
vTaskStartScheduler();
return 0;
}
CSK6 提供了 3 组 I2S,分别为 I2S0~2,主要特性如下:
枚举值 | 说明 |
---|---|
CSK_I2S_MODE_MASTER | 主设备 |
CSK_I2S_MODE_SLAVE | 从设备 |
枚举值 | 说明 |
---|---|
CSK_I2S_PROTO_PHILIPS | 标准格式 |
CSK_I2S_PROTO_LEFT | 左对齐 |
CSK_I2S_PROTO_RIGHT | 右对齐 |
CSK_I2S_PROTO_PCMMODE_A | PCM Mode A |
CSK_I2S_PROTO_PCMMODE_B | PCM Mode B |
枚举值 | 说明 |
---|---|
CSK_I2S_DATA_FORMAT_DUAL_16BIT | 16bit |
CSK_I2S_DATA_FORMAT_24BIT_HIGH | 24bit |
CSK_I2S_DATA_FORMAT_32BIT | 32bit |
CSK_I2S_DATA_FORMAT_24BIT_LOW | 24bit |
CSK_I2S_DATA_FORMAT_20BIT_HIGH | 20bit |
CSK_I2S_DATA_FORMAT_20BIT_LOW | 20bit |
枚举值 | 说明 |
---|---|
CSK_I2S_RXCH_SEPA | 分离 |
CSK_I2S_RXCH_MIXED | 混合 |
枚举值 | 说明 |
---|---|
CSK_I2S_TXCH_MONO_SRC_MONO | mono,数据送到 mono 或者 L/R 声道之一 |
CSK_I2S_TXCH_STEREO_SRC_MONO | mono,数据同时送到 L&R 声道 |
CSK_I2S_TXCH_STEREO_SRC_STEREO | stereo,数据分别送到 L&R 声道 |
枚举值 | 说明 |
---|---|
CSK_I2S_BIT_ORDER_MSB | 高位在前 |
CSK_I2S_BIT_ORDER_LSB | 地位在前 |
I2S 接口暂不支持对外开放。
通过 I2S 接口获取原始和经过算法的音频时,CSK6 作为主设备进行音频的发送,采用 DSP/PCM Mode A 的短帧模式。
Slot-1 | Slot-2 | Slot-3 | Slot-4 | Slot-5 | Slot-6 | Slot-7 | Slot-8 |
---|---|---|---|---|---|---|---|
Mic1 | Mic2 | Ref | 保留 | Ivw1 | Ivw2 | Ivw3 | Aec |
SPI 外设是我们常用的外设功能之一,CSK6 SDK 支持 SPI 外设功能,本章节通过示例介绍 SPI 外设的基本使用方法。
CSK6 芯片有两组 SPI 硬件外设,SPI0 和 SPI1。
CSK6 SPI 驱动功能特性如下:
枚举值 | 说明 |
---|---|
CSK_SPI_MODE_MASTER | 配置为主模式 |
CSK_SPI_MODE_SLAVE | 配置为从模式 |
枚举值 | 说明 |
---|---|
CSK_SPI_TXIO_DMA | 数据发送使用 DMA 传输 |
CSK_SPI_TXIO_PIO | 数据发送使用外设 IO |
CSK_SPI_TXIO_BOTH | 数据发生使用 DMA 或者外设 IO,首选 DMA,若 DMA不能用则使用外设 IO |
CSK_SPI_TXIO_AUTO | 数据发生使用 DMA 或者外设 IO,首选 DMA,若 DMA不能用则使用外设 IO |
CSK_SPI_RXIO_DMA | 与 Tx 相同 |
CSK_SPI_RXIO_PIO | 与 Tx 相同 |
CSK_SPI_RXIO_BOTH | 与 Tx 相同 |
CSK_SPI_RXIO_AUTO | 与 Tx 相同 |
CSK_SPI_CPOL0_CPHA0 | 配置为 SPI Mode0 |
CSK_SPI_CPOL0_CPHA1 | 配置为 SPI Mode1 |
CSK_SPI_CPOL1_CPHA0 | 配置为 SPI Mode2 |
CSK_SPI_CPOL1_CPHA1 | 配置为 SPI Mode3 |
CSK_SPI_DATA_BITS(n) | 单次传输数据长度配置,n仅支持(1 <= n <= 32) |
CSK_SPI_MSB_LSB | SPI Bit order from MSB to LSB (default) |
CSK_SPI_LSB_MSB | SPI Bit order from LSB to MSB |
CSK_SPI_SET_BUS_SPEED | 配置 SPI 时钟,仅在主模式下支持 |
CSK_SPI_GET_BUS_SPEED | 获取 SPI 的时钟 |
CSK_SPI_ABORT_TRANSFER | 终止 SPI 传输 |
CSK_SPI_RESET_FIFO | 复位 SPI FIFO |
枚举值 | 说明 |
---|---|
CSK_SPI_EVENT_TRANSFER_COMPLETE | 数据传输完成 |
CSK_SPI_EVENT_DATA_LOST | 数据丢失 |
void* SPI0();
void* SPI1();
返回值:void *
, 指向 SPI 实例的句柄
int32_t SPI_Initialize(void *spi_dev, CSK_SPI_SignalEvent_t cb_event, uint32_t usr_param);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
spi_dev | void * | SPI 实例句柄 |
cb_event | CSK_SPI_SignalEvent_t | 事件回调函数 |
usr_param | void * | 事件回调函数参数 |
int32_t SPI_Uninitialize(void *spi_dev);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
spi_dev | void * | SPI 实例句柄 |
int32_t SPI_PowerControl(void *spi_dev, CSK_POWER_STATE state)
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
spi_dev | void * | SPI 实例句柄 |
state | CSK_POWER_STATE | 使能状态 CSK_POWER_OFF:失能状态 CSK_POWER_LOW:低功耗状态 CSK_POWER_FULL:全功能状态 |
int32_t SPI_Control(void *spi_dev, uint32_t control, uint32_t arg);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
spi_dev | void * | SPI 实例句柄 |
control | uint32_t | 配置参数 |
arg | uint32_t | 可选参数 |
int32_t SPI_Transfer(void *spi_dev, const void *data_out, void *data_in, uint32_t num);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
spi_dev | void * | SPI 实例句柄 |
data_out | void * | 发送数据缓冲区 |
data_in | void * | 接收数据缓冲区 |
num | uint32_t | 发送和接收的数据长度 |
uint32_t SPI_GetDataCount(void *spi_dev);
int32_t
, 数据发送或接收成功的个数参数名 | 类型 | 说明 |
---|---|---|
spi_dev | void * | SPI 实例句柄 |
本示例基于两个 CSK6-NanoKit 开发板实现 SPI 数据的通信,其中一个作为 SPI 主设备,另一设备作为从设备,实现该示例需要以下准备工作:
2个 CSK6-NanoKit 开发板
使用杜邦线将 spi0(GPIO_A_15 sclk, GPIO_A_16 cs, GPIO_A_17 miso, GPIO_A_18 mosi)
和spi0(GPIO_A_15 sclk, GPIO_A_16 cs, GPIO_A_17 miso, GPIO_A_18 mosi)
连接,接线方式如下图示:
使用全双工通信方式,实现主机给从机发送数据并接收从机发过来的数据,等待接收完成后,主机端使用接收到的数据与从机发送过来的数据进行比较,从机端使用接收到的数据与主机端发送的数据进行比较,若接收到的数据与发送端的数据比较完全相同,则我们认为数据传输完成。
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <shell.h>
#include "venus_ap.h"
#include "IOMuxManager.h"
#include "Driver_SPI.h"
#include "lisa_log.h"
#include "lisa_typedef.h"
#include "lisa_thread.h"
#include "lisa_mem.h"
#include "event_groups.h"
#define SPI0_CLK_PIN (15)
#define SPI0_CS_PIN (16)
#define SPI0_MISO_PIN (17)
#define SPI0_MOSI_PIN (18)
#if (IC_BOARD == 0)
#define SPI0_BUS_SPEED (1000000) // default set to 1MHz
#else
#define SPI0_BUS_SPEED (10000000) // default set to 10MHz on ASIC
#endif
#define SPI0_BUF_SIZE (64) // in word(4 bytes)
#define SPI_MASETER_SEND_DONE (1 << 0)
#define SPI_MASETER_RECV_DONE (1 << 1)
#define SPI_SLAVE_SEND_DONE (1 << 2)
#define SPI_SLAVE_RECV_DONE (1 << 3)
#define SPI_XFER_DONE (1 << 4)
//SPI state
typedef enum {
SPI_STATE_UNKNOWN = 0,
SPI_STATE_INITIALIZED,
SPI_STATE_SENDING, // send is ongoing
SPI_STATE_SEND_DONE, // send is done
SPI_STATE_RECVING, // receive is ongoing
SPI_STATE_RECV_DONE, // receive is done
SPI_STATE_XFERING, // xfering = sending & receiving
SPI_STATE_XFER_DONE, // xfer is done
SPI_STATE_COUNT
} SPI_STATE;
#define TAG "spi_demo"
static bool s_as_master = 0;
static bool s_spi_testing = false;
//SPI master/slave state
static SPI_STATE spi_state_m = SPI_STATE_UNKNOWN;
static SPI_STATE spi_state_s = SPI_STATE_UNKNOWN;
static _DMA_PRAM uint32_t buf_send_m[SPI0_BUF_SIZE]; // buffer for master send
static _DMA_PRAM uint32_t buf_recv_m[SPI0_BUF_SIZE]; // buffer for master receive
static _DMA_PRAM uint32_t buf_send_s[SPI0_BUF_SIZE]; // buffer for slave send
static _DMA_PRAM uint32_t buf_recv_s[SPI0_BUF_SIZE]; // buffer for slave receive
static EventGroupHandle_t g_event_group = NULL;
//SPI master event callback
static void SPI_DrvEvent_m (uint32_t event, uint32_t usr_param)
{
BaseType_t prio = pdFALSE;
void *spi_dev = (void *)usr_param;
assert(spi_dev != NULL);
///传输失败
if( !(event & CSK_SPI_EVENT_TRANSFER_COMPLETE) )
{
CSK_SPI_STATUS status;
status.all = 0;
SPI_GetStatus(spi_dev, &status);
LISA_LOGD(TAG, "%s: event = 0x%x (status = 0x%x), other than TRANSFER_COMPLETE!",
__func__, event, status.all);
return;
}
if (spi_state_m == SPI_STATE_SENDING)
{
LISA_LOGD(TAG, "%s: Master Send Completed (%d items)!",
__func__, SPI_GetDataCount(spi_dev));
spi_state_m = SPI_STATE_SEND_DONE;
xEventGroupSetBitsFromISR(g_event_group, SPI_MASETER_SEND_DONE, &prio);
portYIELD_FROM_ISR(prio);
}
else if (spi_state_m == SPI_STATE_RECVING)
{
LISA_LOGD(TAG, "%s: Master Receive Completed (%d items)!",
__func__, SPI_GetDataCount(spi_dev));
spi_state_m = SPI_STATE_RECV_DONE;
}
else if (spi_state_m == SPI_STATE_XFERING)
{
LISA_LOGD(TAG, "%s: Master duplex Xfer Completed (%d items)!",
__func__, SPI_GetDataCount(spi_dev));
spi_state_m = SPI_STATE_XFER_DONE;
xEventGroupSetBitsFromISR(g_event_group, SPI_XFER_DONE, &prio);
portYIELD_FROM_ISR(prio);
}
return;
}
//SPI slave event callback
static void SPI_DrvEvent_s (uint32_t event, uint32_t usr_param)
{
BaseType_t prio = pdFALSE;
void *spi_dev = (void *)usr_param;
assert(spi_dev != NULL);
///传输失败
if( !(event & (CSK_SPI_EVENT_TRANSFER_COMPLETE)) )
{
CSK_SPI_STATUS status;
status.all = 0;
SPI_GetStatus(spi_dev, &status);
LISA_LOGD(TAG, "%s: event = 0x%x (status = 0x%x), NOT TRANSFER_COMPLETE!",
__func__, event, status.all);
return;
}
if (spi_state_s == SPI_STATE_SENDING)
{
LISA_LOGD(TAG, "%s: Slave Send Completed! (%d items)",
__func__, SPI_GetDataCount(spi_dev));
spi_state_s = SPI_STATE_SEND_DONE;
}
else if (spi_state_s == SPI_STATE_RECVING)
{
LISA_LOGD(TAG, "%s: Slave Receive Completed! (%d items)",
__func__, SPI_GetDataCount(spi_dev));
spi_state_s = SPI_STATE_RECV_DONE;
xEventGroupSetBitsFromISR(g_event_group, SPI_SLAVE_RECV_DONE, &prio);
portYIELD_FROM_ISR(prio);
}
else if (spi_state_s == SPI_STATE_XFERING)
{
LISA_LOGD(TAG, "%s: Slave duplex Xfer Completed (%d items)!",
__func__, SPI_GetDataCount(spi_dev));
spi_state_s = SPI_STATE_XFER_DONE;
xEventGroupSetBitsFromISR(g_event_group, SPI_XFER_DONE, &prio);
portYIELD_FROM_ISR(prio);
}
return;
}
static void * open_spi(uint32_t index, bool as_master, emIOMode txmode, emIOMode rxmode,
uint32_t frm_fmt, uint32_t data_bits, bool msb_order, uint32_t bus_speed)
{
int32_t ret;
void* spi_dev = NULL;
uint32_t control = 0;
//NOTE: set interrupt priority of SPI slave to higher, and set SPI master to default,
// so that interrupts of SPI slave can be serviced first, to prevent data overflow or underflow...
if (index == 0)
{
spi_dev = SPI0();
if (txmode == PIO_IO || rxmode == PIO_IO)
NVIC_SetPriority(IRQ_SPI0_VECTOR, as_master ? DEF_INTERRUPT_PRIORITY : DEF_INTERRUPT_PRIORITY - 1);
}
else if (index == 1)
{
spi_dev = SPI1();
if (txmode == PIO_IO || rxmode == PIO_IO)
NVIC_SetPriority(IRQ_SPI1_VECTOR, as_master ? DEF_INTERRUPT_PRIORITY : DEF_INTERRUPT_PRIORITY - 1);
}
else
{
LISA_LOGD(TAG, "%s: illegal SPI device (index = %d)!", __func__, index);
return NULL;
}
//master or slave
control = (as_master ? CSK_SPI_MODE_MASTER : CSK_SPI_MODE_SLAVE);
// tx mode
switch (txmode)
{
case DMA_IO:
control |= CSK_SPI_TXIO_DMA;
break;
case PIO_IO:
control |= CSK_SPI_TXIO_PIO;
break;
case NO_IO:
default:
control |= CSK_SPI_TXIO_AUTO;
}
// rx mode
switch (rxmode) {
case DMA_IO:
control |= CSK_SPI_RXIO_DMA;
break;
case PIO_IO:
control |= CSK_SPI_RXIO_PIO;
break;
case NO_IO:
default:
control |= CSK_SPI_RXIO_AUTO;
}
// frame format
frm_fmt &= CSK_SPI_FRAME_FORMAT_Msk;
if (frm_fmt == 0 || frm_fmt > CSK_SPI_CPOL1_CPHA1) {
LISA_LOGD(TAG, "%s: illegal frame format!\r\n", __func__);
return NULL;
}
control |= frm_fmt;
// data bits
if (data_bits != 40 && (data_bits == 0 || data_bits > 32)) {
LISA_LOGD(TAG, "%s: illegal data_bits (%d)!\r\n", __func__, data_bits);
return NULL;
}
control |= CSK_SPI_DATA_BITS( data_bits );
control |= (msb_order ? CSK_SPI_MSB_LSB : CSK_SPI_LSB_MSB);
ret = SPI_Initialize(spi_dev, (as_master ? SPI_DrvEvent_m : SPI_DrvEvent_s), (uint32_t)spi_dev);
if (ret != CSK_DRIVER_OK) {
LISA_LOGD(TAG, "%s: SPI_Initialize (spi_no = %d) call failed!!\r\n", __func__, index);
return NULL;
}
ret = SPI_PowerControl(spi_dev, CSK_POWER_FULL);
if (ret != CSK_DRIVER_OK) {
LISA_LOGD(TAG, "%s: SPI_PowerControl (spi_no = %d) call failed!!\r\n", __func__, index);
return NULL;
}
ret = SPI_Control(spi_dev, control, bus_speed);
if (ret != CSK_DRIVER_OK) {
LISA_LOGD(TAG, "%s: SPI_Control (spi_no = %d) call failed!!\r\n", __func__, index);
return NULL;
}
if (as_master)
spi_state_m = SPI_STATE_INITIALIZED;
else {
spi_state_s = SPI_STATE_INITIALIZED;
}
return spi_dev;
}
static void spi0_init_iomux(void)
{
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, SPI0_CLK_PIN, CSK_IOMUX_FUNC_ALTER6); // CLK
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, SPI0_CS_PIN, CSK_IOMUX_FUNC_ALTER6); // CS
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, SPI0_MOSI_PIN, CSK_IOMUX_FUNC_ALTER6); // MOSI
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, SPI0_MISO_PIN, CSK_IOMUX_FUNC_ALTER6); // MISO
}
static void _handle_spi_demo_start(void *arg)
{
void *spi_dev = NULL;
uint32_t data_bits = 8;
uint8_t *buf8 = NULL;
int i = 0;
uint32_t count = 0, recv_cnt = 0;
EventBits_t r_event = 0;
int32_t ret = 0;
///1.初始化引脚
spi0_init_iomux();
///2.初始化spi
spi_dev = open_spi(0, s_as_master, DMA_IO, DMA_IO, CSK_SPI_CPOL0_CPHA1, data_bits, true, SPI0_BUS_SPEED);
if(!spi_dev)
{
LISA_LOGE(TAG, "open spi0 failed");
s_spi_testing = false;
return;
}
///初始化缓冲区
buf8 = (uint8_t*)buf_send_m; // buffer for master send
buf8[0] = 0xa5;
for (i = 1; i < sizeof(buf_send_m); i++) {
buf8[i] = (i*2+1) & 0xFF;
}
buf8 = (uint8_t*)buf_send_s; // buffer for slave send
buf8[0] = 0xbd;
for (i=1; i < sizeof(buf_send_s); i++) {
buf8[i] = (i*2+1) & 0xFF;
}
///创建事件组
g_event_group = xEventGroupCreate();
if(g_event_group == NULL)
{
LISA_LOGE(TAG, "create event group failed");
s_spi_testing = false;
return;
}
while(true)
{
memset(buf_recv_m, 0, sizeof(buf_recv_m)); // buffer for master receive
memset(buf_recv_s, 0, sizeof(buf_recv_s)); // buffer for slave receive
count = SPI0_BUF_SIZE;
spi_state_s = SPI_STATE_XFERING;
spi_state_m = SPI_STATE_XFERING;
if(!s_as_master)
{
///从机发送并接收
SPI_Transfer(spi_dev, buf_send_s, buf_recv_s, count);
}
else
{
///主机发送并接收
SPI_Transfer(spi_dev, buf_send_m, buf_recv_m, count);
}
///等待传输完成
r_event = xEventGroupWaitBits(g_event_group, SPI_XFER_DONE, pdTRUE, pdTRUE, portMAX_DELAY);
if(r_event & SPI_XFER_DONE)
{
recv_cnt = SPI_GetDataCount(spi_dev);
if(recv_cnt == count)
{
if(s_as_master)
{
if(memcmp(buf_send_s, buf_recv_m, recv_cnt))
{
LISA_LOGW(TAG, "Error: master recv differed slave send!");
}
else
{
LISA_LOGI(TAG, "Success: master is same slave");
}
}
else
{
if(memcmp(buf_send_m, buf_recv_s, recv_cnt))
{
LISA_LOGW(TAG, "Error: slave recv differed master send!");
}
else
{
LISA_LOGI(TAG, "Success: slave recv is same master send");
}
}
}
else
{
LISA_LOGW(TAG, "Error: Master sent %d data, but slave received %d data!", count, recv_cnt);
}
}
r_event = 0;
if(s_as_master)
lisa_thread_mdelay(1500);
}
}
void shell_spi_demo_test(bool master)
{
SHELL_ITEM_EXPORT("demo.spi", shell_spi_demo_test, "spi demo test");
LISA_LOGD(TAG, "spi_demo_test start");
if (s_spi_testing) {
LISA_LOGD(TAG, "spi_demo_test is started");
return;
}
s_spi_testing = true;
s_as_master = master;
lisa_thread_attr_t thread_attr;
thread_attr.name = "spi demo";
thread_attr.stack_size = 2048;
thread_attr.priority = LISA_OS_PRIORITY_NORMAL;
lisa_thread_t *spi_thread = lisa_thread_create(&thread_attr, _handle_spi_demo_start, NULL);
if (spi_thread == NULL)
{
LISA_LOGE(TAG, "create spi demo thread error");
}
}
demo.spi <as_master>
as_master为0表示当前为从机端;as_master为1表示当前为主机端
CSK6 提供了 3 组UART,分别为 UART0 ~ 2,主要特性如下:
全双工异步通信
波特率最高可支持到 3Mbps
可配置的数据位,支持 5/6/7/8 位
可配置的校验,支持奇偶校验
可配置的停止位,支持 1/1.5/2 位
支持硬件流控 CTS 和 RTS
支持 DMA 数据传输
枚举值 | 说明 |
---|---|
CSK_UART_DATA_BITS_5 | 5位 |
CSK_UART_DATA_BITS_6 | 6位 |
CSK_UART_DATA_BITS_7 | 7位 |
CSK_UART_DATA_BITS_8 | 8位,默认值 |
枚举值 | 说明 |
---|---|
CSK_UART_PARITY_NONE | 无校验,默认值 |
CSK_UART_PARITY_EVEN | 偶校验 |
CSK_UART_PARITY_ODD | 奇校验 |
枚举值 | 说明 |
---|---|
CSK_UART_STOP_BITS_1 | 1位,默认值 |
CSK_UART_STOP_BITS_2 | 2位 |
CSK_UART_STOP_BITS_1_5 | 1.5位 |
枚举值 | 说明 |
---|---|
CSK_UART_FLOW_CONTROL_NONE | 无流控,默认值 |
CSK_UART_FLOW_CONTROL_RTS | RTS |
CSK_UART_FLOW_CONTROL_CTS | CTS |
CSK_UART_FLOW_CONTROL_RTS_CTS | RTS和CTS |
void *UART0(void);
void *UART1(void);
void *UART2(void);
void *
, 指向 UART 实例的句柄int32_t UART_Initialize(void *res, CSK_UART_SignalEvent_t cb_event, void* workspace);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | UART实例句柄 |
cb_event | CSK_UART_SignalEvent_t | 事件回调函数 |
workspace | void* | 固定传入 NULL |
int32_t UART_Uninitialize(void *res);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | UART实例句柄 |
int32_t UART_PowerControl(void *res, CSK_POWER_STATE state);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | UART实例句柄 |
state | CSK_POWER_STATE | 使能状态 CSK_POWER_OFF:失能状态 CSK_POWER_LOW:低功耗状态 CSK_POWER_FULL:全功能状态 |
int32_t UART_Control(void *res, uint32_t control, uint32_t arg);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | UART实例句柄 |
control | uint32_t | 配置参数 |
arg | uint32_t | 可选参数 |
int32_t UART_Send(void *res, const void *data, uint32_t num);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | UART实例句柄 |
data | void * | 指向发送缓冲区的指针 |
num | uint32_t | 发送数据大小 |
int32_t UART_Receive(void *res, void *data, uint32_t num);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | UART 实例句柄 |
data | void * | 指向接收缓冲区的指针 |
num | uint32_t | 接收数据的大小 |
uint32_t UART_GetTxCount(void *res);
uint32_t
,发送的字节数参数名 | 类型 | 说明 |
---|---|---|
res | void * | UART 实例句柄 |
uint32_t UART_GetRxCount(void *res);
uint32_t
,接收的字节数参数名 | 类型 | 说明 |
---|---|---|
res | void | UART实例句柄 |
int32_t UART_GetStatus(void *res, CSK_UART_STATUS* stat);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | UART实例句柄 |
stat | CSK_UART_STATUS* | 指向运行状态的指针 |
示例基于 CSK6012-NanoKit V1 硬件进行演示。
串口数据格式:115200,8N1。
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <shell.h>
#include "IOMuxManager.h"
#include "Driver_UART.h"
#include "lisa_log.h"
#include "lisa_typedef.h"
#include "lisa_thread.h"
#include "lisa_mem.h"
#define UART_TAG "uart_demo"
#define UART_RECV_BUFFER_SIZE 100
static bool s_uart_testing = false;
static bool s_recv_flag = false;
static void *s_uart_test = NULL;
static char s_buffer[UART_RECV_BUFFER_SIZE] = {0};
static void uart_demo_evt(uint32_t event, void *workspace)
{
switch (event) {
case CSK_UART_EVENT_SEND_COMPLETE:
break;
case CSK_UART_EVENT_RECEIVE_COMPLETE:
break;
case CSK_UART_EVENT_RX_TIMEOUT:
s_recv_flag = true;
break;
default:
LISA_LOGW(UART_TAG, "uart unmasked event: %#x", event);
break;
}
}
void uart_demo_init()
{
if (s_uart_test) return;
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 0, 3);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 1, 3);
s_uart_test = UART1();
UART_Initialize(s_uart_test, uart_demo_evt, s_uart_test);
UART_PowerControl(s_uart_test, CSK_POWER_FULL);
UART_Control(s_uart_test, CSK_UART_MODE_ASYNCHRONOUS_TIMEOUT | CSK_UART_DATA_BITS_8
| CSK_UART_PARITY_NONE | CSK_UART_STOP_BITS_1 | CSK_UART_FLOW_CONTROL_NONE
| CSK_UART_Function_CONTROL_Int, 115200);
UART_Control(s_uart_test, CSK_UART_CONTROL_TX, 1);
UART_Control(s_uart_test, CSK_UART_CONTROL_RX, 1);
}
static void _handle_uart_demo_start(void *arg)
{
uart_demo_init();
UART_Receive(s_uart_test, s_buffer, UART_RECV_BUFFER_SIZE);
char *str = "hello world!!!";
int str_len = strlen(str);
int recv_count;
lisa_thread_mdelay(1000);
UART_Send(s_uart_test, str, str_len);
while (true) {
if (s_recv_flag) {
s_recv_flag = false;
recv_count = UART_GetRxCount(s_uart_test);
LISA_LOGD(UART_TAG, "receive count:%d content:%s", recv_count, s_buffer);
memset(s_buffer, 0 , UART_RECV_BUFFER_SIZE);
UART_Receive(s_uart_test, s_buffer, UART_RECV_BUFFER_SIZE);
lisa_thread_mdelay(1000);
UART_Send(s_uart_test, str, str_len);
}
lisa_thread_mdelay(500);
}
}
void shell_uart_demo_test()
{
SHELL_ITEM_EXPORT("demo.uart", shell_uart_demo_test, "uart demo test");
LISA_LOGD(UART_TAG, "uart_demo_test start");
if (s_uart_testing) {
LISA_LOGD(UART_TAG, "uart_demo_test is started");
return;
}
s_uart_testing = true;
lisa_thread_attr_t thread_attr;
thread_attr.name = "uart demo";
thread_attr.stack_size = 2048;
thread_attr.priority = LISA_OS_PRIORITY_NORMAL;
lisa_thread_t *thread = lisa_thread_create(&thread_attr, _handle_uart_demo_start, NULL);
if (thread == NULL) {
LISA_LOGE(UART_TAG, "create uart demo thread error");
}
}
ADC(Analog to Digital) 模拟转数字是经常使用的外设,本章节讲解如何使用CSK6 SDK的ADC接口实现外部电压的检测。
CSK6 ADC驱动具有如下特性:
值 | 说明 |
---|---|
CSK_GPADC_TRIGGER_HARDWARE_Enable | 硬件触发 |
CSK_GPADC_TRIGGER_GPT_Enable | 软件触发 |
值 | 说明 |
---|---|
CSK_GPADC_SAMPLETIME_4 | 4个时钟周期 |
CSK_GPADC_SAMPLETIME_8 | 8个时钟周期 |
CSK_GPADC_SAMPLETIME_16 | 16个时钟周期 |
CSK_GPADC_SAMPLETIME_32 | 32个时钟周期 |
值 | 说明 |
---|---|
CSK_GPADC_CLKFREQ_24M | 24M |
CSK_GPADC_CLKFREQ_12M | 12M |
CSK_GPADC_CLKFREQ_6M | 6M |
CSK_GPADC_CLKFREQ_3M | 3M |
值 | 说明 |
---|---|
CSK_GPADC_CHANNEL_SEL_0 | 通道0 |
CSK_GPADC_CHANNEL_SEL_1 | 通道1 |
CSK_GPADC_CHANNEL_SEL_2 | 通道2 |
CSK_GPADC_CHANNEL_SEL_3 | 通道3 |
CSK_GPADC_CHANNEL_SEL_VDDIO | VDDIO通道 |
CSK_GPADC_CHANNEL_SEL_VCC | VCC通道 |
CSK_GPADC_CHANNEL_SEL_KEYSENSE | KEYSENSE通道 |
CSK_GPADC_CHANNEL_SEL_TEMP | TEMP通道 |
CSK_GPADC_CHANNEL_SEL_CVD0 | CVD通道0 |
CSK_GPADC_CHANNEL_SEL_CVD1 | CVD通道1 |
CSK_GPADC_CHANNEL_SEL_CVD2 | CVD通道2 |
CSK_GPADC_CHANNEL_SEL_CVD3 | CVD通道3 |
CSK_GPADC_CHANNEL_SEL_CVD4 | CVD通道4 |
CSK_GPADC_CHANNEL_SEL_CVD5 | CVD通道5 |
CSK_GPADC_CHANNEL_SEL_ALL | 所有ADC通道 |
值 | 说明 |
---|---|
CSK_GPADC_INPUT_MODE_Diff | 差分 |
CSK_GPADC_INPUT_MODE_Single | 单端 |
值 | 说明 |
---|---|
CSK_GPADC_VREF_SEL_1_25V | 内部1.25V |
CSK_GPADC_VREF_SEL_VDDIO | VDDIO |
CSK_GPADC_VREF_SEL_EXT | 外部VREF |
值 | 说明 |
---|---|
CSK_GPADC_DMA_ENABLE | 使能DMA传输 |
CSK_GPADC_DMA_DISABLE | 禁用DMA传输 |
void* GPADC(void);
void *
, 指向 GPADC 实例的句柄int32_t HAL_GPADC_Initialize(void *res);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | ADC 实例句柄 |
int32_t HAL_GPADC_Uninitialize(void *res);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | ADC 实例句柄 |
int32_t HAL_GPADC_Control(void* res, uint32_t control);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | ADC 实例句柄 |
control | uint32_t | 配置参数 |
uint32_t HAL_GPADC_Start(void* res);
uint32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | ADC 实例句柄 |
uint32_t HAL_GPADC_Stop(void* res);
uint32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | ADC 实例句柄 |
uint32_t HAL_GPADC_PollForConversion(void* res, uint32_t Timeout);
uint32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | ADC 实例句柄 |
Timeout | uint32_t | 超时时间 |
uint16_t HAL_GPADC_GetValue(void* res, uint32_t channelnum);
uint16_t
, adc
的采样值参数名 | 类型 | 说明 |
---|---|---|
res | void * | ADC 实例句柄 |
channelnum | uint32_t | channel号 |
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <shell.h>
#include "IOMuxManager.h"
#include "Driver_GPADC.h"
#include "lisa_log.h"
#include "lisa_typedef.h"
#include "lisa_thread.h"
#include "lisa_mem.h"
#define GPADC_TAG "gpadc_demo"
static bool s_gpadc_testing = false;
int gpadc_init(uint32_t chn_sel)
{
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_B, 6, CSK_IOMUX_FUNC_ALTER16);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_B, 7, CSK_IOMUX_FUNC_ALTER16);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_B, 8, CSK_IOMUX_FUNC_ALTER16);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_B, 9, CSK_IOMUX_FUNC_ALTER16);
HAL_GPADC_Initialize(GPADC());
HAL_GPADC_Control(GPADC(), CSK_GPADC_SAMPLETIME_8 | CSK_GPADC_CLKFREQ_12M | chn_sel |
CSK_GPADC_INPUT_MODE_Single | CSK_GPADC_VREF_SEL_1_25V | CSK_GPADC_DMA_DISABLE);
return CSK_DRIVER_OK;
}
/**
* adc 采样值转电压(mV)
*/
int adc_raw_to_millivolts(int32_t adc_value, int32_t *mv)
{
if ((0 < adc_value) && (adc_value < 4096)) {
*mv = (adc_value - 2048) * 3300 / 2048;
return 0;
}
return -1;
}
static void _handle_gpadc_demo_start(void *arg)
{
gpadc_init(CSK_GPADC_CHANNEL_SEL_ALL);
uint16_t adc_value;
int16_t adc_mv;
while (true) {
HAL_GPADC_Start(GPADC());
HAL_GPADC_PollForConversion(GPADC(), 0);
adc_value = HAL_GPADC_GetValue(GPADC(), CSK_GPADC_CHANNEL_SEL_0);
adc_raw_to_millivolts(adc_value, &adc_mv);
LISA_LOGD(GPADC_TAG, "channel[0x%x], adc_value[%d]= %d mV", CSK_GPADC_CHANNEL_SEL_0, adc_value, adc_mv);
adc_value = HAL_GPADC_GetValue(GPADC(), CSK_GPADC_CHANNEL_SEL_1);
adc_raw_to_millivolts(adc_value, &adc_mv);
LISA_LOGD(GPADC_TAG, "channel[0x%x], adc_value[%d]= %d mV", CSK_GPADC_CHANNEL_SEL_1, adc_value, adc_mv);
adc_value = HAL_GPADC_GetValue(GPADC(), CSK_GPADC_CHANNEL_SEL_2);
adc_raw_to_millivolts(adc_value, &adc_mv);
LISA_LOGD(GPADC_TAG, "channel[0x%x], adc_value[%d]= %d mV", CSK_GPADC_CHANNEL_SEL_2, adc_value, adc_mv);
adc_value = HAL_GPADC_GetValue(GPADC(), CSK_GPADC_CHANNEL_SEL_3);
adc_raw_to_millivolts(adc_value, &adc_mv);
LISA_LOGD(GPADC_TAG, "channel[0x%x], adc_value[%d]= %d mV", CSK_GPADC_CHANNEL_SEL_3, adc_value, adc_mv);
lisa_thread_mdelay(1000);
}
}
void shell_gpadc_demo_test()
{
SHELL_ITEM_EXPORT("demo.gpadc", shell_gpadc_demo_test, "gpadc demo test");
printk("gpadc_demo_test start\n");
if (s_gpadc_testing) {
printk("gpadc_demo_test is started\n");
return;
}
s_gpadc_testing = true;
lisa_thread_attr_t thread_attr;
thread_attr.name = "gpadc demo";
thread_attr.stack_size = 2048;
thread_attr.priority = LISA_OS_PRIORITY_NORMAL;
lisa_thread_t *thread = lisa_thread_create(&thread_attr, _handle_gpadc_demo_start, NULL);
if (thread == NULL) {
LISA_LOGE(GPADC_TAG, "create gpadc demo thread error");
}
}
PWM 是常用的外设功能之一,CSK6 总共有8组 PWM 输出口,其 33 个管脚均可配置为 PWM 输出。
不同管脚对应的通道如下:
通道组 | 引脚名称 | 引脚名称 | 引脚名称 | 引脚名称 | 引脚名称 |
---|---|---|---|---|---|
通道0 | SWDCLK | GPIOA_08 | GPIOA_16 | GPIOB_08 | GPIOB_00 |
通道1 | SWDIO | GPIOA_09 | GPIOA_17 | GPIOB_07 | |
通道2 | GPIOA_02 | GPIOA_10 | GPIOA_18 | GPIOB_06 | |
通道3 | GPIOA_03 | GPIOA_11 | GPIOA_19 | GPIOB_05 | |
通道4 | GPIOA_04 | GPIOA_12 | GPIOA_20 | GPIOB_04 | |
通道5 | GPIOA_05 | GPIOA_13 | GPIOB_03 | USB_DM | |
通道6 | GPIOA_06 | GPIOA_14 | GPIOB_02 | USB_DP | |
通道7 | GPIOA_07 | GPIOA_15 | GPIOB_01 | GPIOB_09 |
枚举值 | 说明 |
---|---|
CSK_GPT_PWM_MODE | 指定 GPT 为 PWM 模式 |
枚举值 | 说明 |
---|---|
CSK_GPT_PWM_CLKSRC_PCLK | peripheral clock,系统外设时钟,SDK 中默认是 100000000Hz |
CSK_GPT_PWM_CLKSRC_EXT | external clock: 32.768KHz |
CSK_GPT_PWM_CLKSRC_XTAL | crystal clock,外部晶振输入时钟,SDK 中是 24000000Hz |
枚举值 | 说明 |
---|---|
CSK_GPT_PWM_CLKDIV_1 | CLKSRC / 1 |
CSK_GPT_PWM_CLKDIV_2 | CLKSRC / 2 |
CSK_GPT_PWM_CLKDIV_4 | CLKSRC / 4 |
CSK_GPT_PWM_CLKDIV_8 | CLKSRC / 8 |
CSK_GPT_PWM_CLKDIV_16 | CLKSRC / 16 |
CSK_GPT_PWM_CLKDIV_32 | CLKSRC / 32 |
CSK_GPT_PWM_CLKDIV_64 | CLKSRC / 64 |
CSK_GPT_PWM_CLKDIV_128 | CLKSRC / 128 |
枚举值 | 说明 |
---|---|
CSK_GPT_PWM_OUTMODE_EDGE_ALIGNED | PWM 边缘对齐 |
CSK_GPT_PWM_OUTMODE_CENTRAL_ALIGNED | PWM 中间对齐 |
枚举值 | 说明 |
---|---|
CSK_GPT_PWM_OUTPOLARITY_LOW | PWM 低电平有效 |
CSK_GPT_PWM_OUTPOLARITY_HIGH | PWM 高电平有效 |
枚举值 | 说明 |
---|---|
CSK_GPT_PWM_OPERATION_MODE_ONEPULSE | 输出一个脉冲模式 |
CSK_GPT_PWM_OPERATION_MODE_PWM | 标准 PWM 模式 |
CSK_GPT_PWM_OPERATION_MODE_LEDC | LEDC 模式 |
CSK_GPT_PWM_OPERATION_MODE_LEDC_NODMA | LEDC 非 DMA 模式 |
CSK_GPT_PWM_OPERATION_MODE_LEDC_DMA | LEDC DMA 模式 |
枚举值 | 说明 |
---|---|
CSK_GPT_LEDC_TRANSFER_MODE_POLLING | 轮询模式 |
CSK_GPT_LEDC_TRANSFER_MODE_INTERRUPT | 中断模式 |
CSK_GPT_LEDC_TRANSFER_MODE_DMA | DMA 模式 |
枚举值 | 说明 |
---|---|
CSK_POWER_OFF | Power off 电源关闭 |
CSK_POWER_LOW | Low Power mode 低电模式 |
CSK_POWER_FULL | Power on 全功耗模式,打开 PWM 电源 |
枚举值 | 说明 |
---|---|
GPT_CHANNEL0 | GPT 通道 0 |
GPT_CHANNEL1 | GPT 通道 1 |
GPT_CHANNEL2 | GPT 通道 2 |
GPT_CHANNEL3 | GPT 通道 3 |
GPT_CHANNEL4 | GPT 通道 4 |
GPT_CHANNEL5 | GPT 通道 5 |
GPT_CHANNEL6 | GPT 通道 6 |
GPT_CHANNEL7 | GPT 通道 7 |
void* GPT0_PWM(void);
void *
, 指向 PWM
实例的句柄int32_t HAL_GPT_PWMInitialize(void *pGpt, void *user_param);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
user_param | void * | 通常传入 NULL,DMA中断回调函数的输入参数 |
int32_t HAL_GPT_PWMUninitialize(void *pGpt);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
int32_t HAL_GPT_PWMPowerControl(void *pGpt, CSK_POWER_STATE state)
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
state | CSK_POWER_STATE | 见 PWM 电源模式 |
int32_t HAL_GPT_PWMControl(void *pGpt, uint32_t control, GPT_CHANNEL_TYPE channel);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
control | uint32_t | 配置 PWM 操控和传输,2.1 - 2.7 参数值或得到 |
channel | GPT_CHANNEL_TYPE | 见 PWM 通道模式 |
int32_t HAL_GPT_SetPWMFreqDuty(void *pGpt, GPT_CHANNEL_TYPE channel, uint32_t freq, uint8_t duty);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
channel | GPT_CHANNEL_TYPE | 见 PWM 通道模式 |
freq | uint32_t | 标准 PWM 输出方波配置频率 |
duty | uint8_t | 标准 PWM 输出方波占空比 0 -100 等于0% -100% |
int32_t HAL_GPT_EnablePWM(void *pGpt, GPT_CHANNEL_TYPE channel);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
channel | GPT_CHANNEL_TYPE | 见 PWM 通道模式 |
int32_t HAL_GPT_DisablePWM(void *pGpt, GPT_CHANNEL_TYPE channel);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
channel | GPT_CHANNEL_TYPE | 见 PWM 通道模式 |
int32_t HAL_GPT_EnableLEDC(void *pGpt, GPT_CHANNEL_TYPE channel);
返回值:int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码
参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
channel | GPT_CHANNEL_TYPE | 见 PWM 通道模式 |
int32_t HAL_GPT_DisableLEDC(void *pGpt, GPT_CHANNEL_TYPE channel);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
channel | GPT_CHANNEL_TYPE | 见 PWM 通道模式 |
int32_t HAL_GPT_LEDCOut(void *pGpt, GPT_CHANNEL_TYPE channel, uint32_t *senddata, uint32_t length);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
channel | GPT_CHANNEL_TYPE | 见 PWM 通道模式 |
senddata | uint32_t * | 发送数据地址 |
length | uint32_t | senddata 指向内存中32位数据个数 |
int32_t HAL_GPT_RegisterLEDCCallback(void *pGpt, GPT_CHANNEL_TYPE channel, CSK_GPT_SignalEvent_t cb_event);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
pGpt | void * | PWM 实例句柄 |
channel | GPT_CHANNEL_TYPE | 见 PWM 通道模式 |
cb_event | CSK_GPT_SignalEvent_t | event callback |
typedef void (*CSK_GPT_SignalEvent_t)(uint32_t event, void *param);
本小节在 CSK6012-NanoKit 开发板上,以下图中⑦ LED 灯(绿) 为例,展示通过标准 PWM ,实现呼吸灯功能的过程。
查看原理图,可以看到 LED1(GREEN)对应 GPIO 引脚为 GPIOB_06,GPIOB_06 对应的PWM通道为通道 2(GPT_CHANNEL2)。
初始化 GPIOB_06 为标准 PWM 输出模式
标准 PWM 输出模式频率为 2000Hz 频率闪烁
以 5% 为单位、50 毫秒为时间间隔,循环升降标准 PWM 的输出脉冲的占空比,通过占空比调整 LED 灯的亮度,实现呼吸灯功能
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <shell.h>
#include "IOMuxManager.h"
#include "Driver_GPT_PWM.h"
#include "lisa_log.h"
#include "lisa_typedef.h"
#include "lisa_thread.h"
#include "lisa_mem.h"
#define PWM_TAG "pwm_demo"
#define PWM_FRQ 2000
// 设置 100 和 0,会变成系统时钟
#define PWM_DUTY_MAX 95
#define PWM_DUTY_MIN 5
#define PWM_DUTY_STEP 5
//LED GREEN GPIOB6
#define PWM_CH2 GPT_CHANNEL2
#define PWM_CH2_PAD (CSK_IOMUX_PAD_B)
#define PWM_CH2_PIN (06)
#define PWM_CH2_SEL (11)
#define PWM_CH PWM_CH2
#define PWM_PAD PWM_CH2_PAD
#define PWM_PIN PWM_CH2_PIN
#define PWM_SEL PWM_CH2_SEL
static bool s_pwm_testing = false;
int gpt_pwm_init(void)
{
uint32_t ret;
HAL_GPT_PWMUninitialize(GPT0_PWM());
/*generate pwm wave*/
ret = HAL_GPT_PWMInitialize(GPT0_PWM(), NULL);
if(ret != CSK_DRIVER_OK)
LISA_LOGE(PWM_TAG, "Error = %d", ret);
ret = HAL_GPT_PWMPowerControl(GPT0_PWM(), CSK_POWER_FULL);
if(ret != CSK_DRIVER_OK)
LISA_LOGE(PWM_TAG, "Error = %d", ret);
ret = HAL_GPT_PWMControl(GPT0_PWM(), CSK_GPT_PWM_MODE | CSK_GPT_PWM_CLKSRC_PCLK | CSK_GPT_PWM_OUTMODE_EDGE_ALIGNED | CSK_GPT_PWM_OUTPOLARITY_LOW |
CSK_GPT_PWM_CLKDIV_4 | CSK_GPT_PWM_OPERATION_MODE_PWM, PWM_CH);
if(ret != CSK_DRIVER_OK)
LISA_LOGE(PWM_TAG, "Error = %d", ret);
ret = HAL_GPT_SetPWMFreqDuty(GPT0_PWM(), PWM_CH, PWM_FRQ, PWM_DUTY_MAX);
if(ret != CSK_DRIVER_OK)
LISA_LOGE(PWM_TAG, "Error = %d", ret);
IOMuxManager_PinConfigure(PWM_PAD, PWM_PIN, PWM_SEL);
HAL_GPT_EnablePWM(GPT0_PWM(), PWM_CH);
return CSK_DRIVER_OK;
}
static void _handle_pwm_demo_start(void *arg)
{
gpt_pwm_init();
int duty_plus = PWM_DUTY_MIN;
int duty_step = 0 - PWM_DUTY_STEP;
while (true) {
lisa_thread_mdelay(50);
// printk("<%d>\n", duty_plus);
HAL_GPT_DisablePWM(GPT0_PWM(), PWM_CH);
HAL_GPT_SetPWMFreqDuty(GPT0_PWM(), PWM_CH, PWM_FRQ, duty_plus);
HAL_GPT_EnablePWM(GPT0_PWM(), PWM_CH);
if (duty_plus == PWM_DUTY_MIN || duty_plus == PWM_DUTY_MAX) {
duty_step = 0 - duty_step;
}
duty_plus += duty_step;
}
}
void shell_pwm_demo_test()
{
SHELL_ITEM_EXPORT("demo.pwm", shell_pwm_demo_test, "pwm demo test");
LISA_LOGD(PWM_TAG, "pwm_demo_test start");
if (s_pwm_testing) {
LISA_LOGD(PWM_TAG, "pwm_demo_test is started");
return;
}
s_pwm_testing = true;
lisa_thread_attr_t thread_attr;
thread_attr.name = "pwm demo";
thread_attr.stack_size = 2048;
thread_attr.priority = LISA_OS_PRIORITY_NORMAL;
lisa_thread_t *thread = lisa_thread_create(&thread_attr, _handle_pwm_demo_start, NULL);
if (thread == NULL) {
LISA_LOGE(PWM_TAG, "create pwm demo thread error");
}
}
本小节演示 LEDC 接口使用。
通过 CSK6012-NanoKit 开发板上的 GPIOA_10口向 12 个级连的 WS2812B(智能外控集成LED光源)组成的灯带发送控制命令,实现彩灯呼吸灯功能。
原理图:
注释:VDD 建议 3.3V
WS2812B bit 格式:
WS2812B 级联后数据传输格式:
调用 LEDC 接口发送数据:
int32_t HAL_GPT_LEDCOut(void *pGpt, GPT_CHANNEL_TYPE channel, uint32_t *senddata, uint32_t length);
senddata: 指向的内存中存储着 12 个的 RGB 数值
length:值为 12,在这个例子里和灯的个数一致
HAL_GPT_LEDCOut 依据 LEDC 数据协议,向 PWM 总线上发送 12 个 24bit,依次通过级联依次把每个灯的 RGB 值发送到对应的灯
要满足 bit 格式符合接收设备 WS2812B 的输入要求
极性选择低电平
计算时钟源的时钟,最小单位的高电平时长要小于 220ns,时钟源的频率要大于 4.545MHz。选取 100000000 / 8 = 12.5MHz 时钟可以满足要求,即 CSK_GPT_PWM_CLKSRC_PCLK | CSK_GPT_PWM_CLKDIV_8
初始化 GPIOA_10为 LEDC 输出模式
配置 LEDC 的输出结束回调函数
3秒内以100个等阶、30毫秒为时间间隔,循环更新12个 LEDC 数控灯的 RGB 数组,实现呼吸灯功能
#include "appinc.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <shell.h>
#include "FreeRTOS.h"
#include "queue.h"
#include "IOMuxManager.h"
#include "Driver_GPT_PWM.h"
#include "lisa_log.h"
#include "lisa_typedef.h"
#include "lisa_thread.h"
#include "lisa_mem.h"
#define TAG "ledc_demo"
#define LEDC_PIN_CFG CSK_IOMUX_PAD_A, 10, CSK_IOMUX_FUNC_ALTER11
//#define LEDC_PIN_CFG CSK_IOMUX_PAD_A, 10, CSK_IOMUX_FUNC_ALTER11
//#define LEDC_PIN_CFG CSK_IOMUX_PAD_B, 6, CSK_IOMUX_FUNC_ALTER11
#define LEDC_PWM_CHN (GPT_CHANNEL2)
#define LEDC_FRM_SIZE (128) // for 32bytes aligned, so here should be multiples of 8(=32/4)
#define LEDC_LED_CNT (12) // max: MAX_BLK_TS
#define LEDC_QUE_SIZE (2) // dma queue size, valids: >1
#define LEDC_LED_BRIGHT (50) // valids: [0,100)
#define LEDC_FADE_STEPS (100) // total steps of fade in&out of one breath frame period
#define LEDC_PERIOD_MS (3000) // total time of fade in&out of one breath frame period
static QueueHandle_t ledq = NULL;
static uint32_t __ALIGNED(32) ctrls[LEDC_QUE_SIZE][LEDC_FRM_SIZE]; // dma needs 32bytes aligned
static void ledc_evt_cb(uint32_t event, void *param)
{
if (event & CSK_GPT_EVENT_LEDC_TX_DONE) {
static uint32_t fpos = 0;
void *const pwm = param;
HAL_GPT_DisableLEDC(pwm, LEDC_PWM_CHN);
if (!xQueueIsQueueFullFromISR(ledq)) {
void *addr = &ctrls[fpos++];
if (fpos >= LEDC_QUE_SIZE)
fpos = 0;
BaseType_t prio = pdFALSE;
xQueueSendFromISR(ledq, &addr, &prio);
portYIELD_FROM_ISR(prio);
}
BaseType_t ret = HAL_GPT_LEDCOut(pwm, LEDC_PWM_CHN, &ctrls[fpos], ARRSIZE(ctrls[0]));
ASSERT(CSK_DRIVER_OK == ret, "pwm.led(%d)", ret);
}
}
static void *ledc_hw_init(void)
{
IOMuxManager_PinConfigure(LEDC_PIN_CFG);
void *pwm = GPT0_PWM();
int ret = HAL_GPT_PWMUninitialize(pwm);
ret = HAL_GPT_PWMInitialize(pwm, pwm);
ASSERT(CSK_DRIVER_OK == ret, "pwm.init(%d)", ret);
ret = HAL_GPT_PWMPowerControl(pwm, CSK_POWER_FULL);
ASSERT(CSK_DRIVER_OK == ret, "pwm.pwr(%d)", ret);
ret = HAL_GPT_PWMControl(pwm, CSK_GPT_PWM_MODE | CSK_GPT_PWM_CLKSRC_PCLK
| CSK_GPT_PWM_OUTMODE_EDGE_ALIGNED | CSK_GPT_PWM_OUTPOLARITY_LOW | CSK_GPT_PWM_CLKDIV_8
| CSK_GPT_PWM_OPERATION_MODE_LEDC | CSK_GPT_LEDC_TRANSFER_MODE_DMA, LEDC_PWM_CHN);
ASSERT(CSK_DRIVER_OK == ret, "pwm.ctrl(%d)", ret);
ret = HAL_GPT_RegisterLEDCCallback(pwm, LEDC_PWM_CHN, ledc_evt_cb);
ASSERT(CSK_DRIVER_OK == ret, "pwm.reg(%d)", ret);
return pwm;
}
static void ledc_data_prepare(uint32_t *pdata, int period)
{
static int tick = 0;
if (++tick >= period) tick = 0;
uint32_t rgb = ((uint32_t)((sin(3.14f * tick / period) * 0.9 + 0.1f) * 2.56f * LEDC_LED_BRIGHT));
for (int grp = 0; grp < LEDC_LED_CNT / 4; grp++) {
for (int led = 0; led < 4; led++)
pdata[grp * 4 + led] = rgb;
rgb <<= 8;
}
}
void ledc_ctrl_task(void *param)
{
memset(ctrls, 0xFF, sizeof(ctrls));
ledq = xQueueCreate(LEDC_QUE_SIZE - 1, sizeof(void *));
ASSERT(ledq, "create");
void *const pwm = ledc_hw_init();
int ret = HAL_GPT_LEDCOut(pwm, LEDC_PWM_CHN, ctrls, ARRSIZE(ctrls[0]));
ASSERT(CSK_DRIVER_OK == ret, "pwm.led(%d)", ret);
while (true) {
void *addr = NULL;
xQueueReceive(ledq, &addr, portMAX_DELAY);
ASSERT(addr, "invalid");
ledc_data_prepare(addr, LEDC_FADE_STEPS);
vTaskDelay(pdMS_TO_TICKS(LEDC_PERIOD_MS / LEDC_FADE_STEPS));
}
//vTaskDelete(NULL);
}
static bool s_ledc_testing = false;
void shell_ledc_demo_test()
{
SHELL_ITEM_EXPORT("demo.ledc", shell_ledc_demo_test, "ledc demo test");
printk("\nledc_demo_test start\n");
if (s_ledc_testing) {
printk("\nledc_demo_test is started\n");
return;
}
s_ledc_testing = true;
lisa_thread_attr_t thread_attr;
thread_attr.name = "ledc demo";
thread_attr.stack_size = 2048;
thread_attr.priority = LISA_OS_PRIORITY_NORMAL;
lisa_thread_t *thread = lisa_thread_create(&thread_attr, ledc_ctrl_task, NULL);
if (thread == NULL) {
LISA_LOGE(TAG, "create adc demo thread error");
}
}
I2C 是我们常用的外设功能之一,CSK6 SDK I2C 外设驱动采用标准的 I2C 总线协议,本节我们将通过示例讲解如何使用 CSK6 SDK 的 I2C API 接口实现数据的收发。
CSK6 芯片有两个 I2C 硬件外设。
CSK6 I2C 驱动功能特性如下:
枚举值 | 说明 |
---|---|
CSK_I2C_ADDRESS_10BIT | 配置是否使用10bit地址,默认为7bit地址 |
枚举值 | 说明 |
---|---|
CSK_I2C_BUS_SPEED_STANDARD | Standard Speed (100kb/s) |
CSK_I2C_BUS_SPEED_FAST | Fast Speed (400kb/s) |
CSK_I2C_BUS_SPEED_FAST_PLUS | Fast + Speed (1Mkb/s) |
枚举值 | 说明 |
---|---|
CSK_I2C_OWN_ADDRESS | 配置 I2C 的从机地址值,若不配置则为 Master 模式 |
CSK_I2C_BUS_SPEED | 配置 I2C 的传输速度 |
CSK_I2C_BUS_CLEAR | 执行总线清除工作,并发送9个时钟脉冲 |
CSK_I2C_ABORT_TRANSFER | 终止 Master/Slave Transmit/Receive |
CSK_I2C_TRANSMIT_MODE | 配置传输模式,arg = 0:中断传输;arg = 1:DMA 传输 |
枚举值 | 说明 |
---|---|
CSK_I2C_EVENT_TRANSFER_DONE | Master/Slave Transmit/Receive finished |
CSK_I2C_EVENT_TRANSFER_INCOMPLETE | Master/Slave Transmit/Receive incomplete transfer |
CSK_I2C_EVENT_SLAVE_TRANSMIT | Slave Transmit operation requested |
CSK_I2C_EVENT_SLAVE_RECEIVE | Slave Receive operation requested |
CSK_I2C_EVENT_ADDRESS_NACK | Address not acknowledged from Slave |
CSK_I2C_EVENT_GENERAL_CALL | General Call indication |
CSK_I2C_EVENT_ARBITRATION_LOST | Master lost arbitration |
CSK_I2C_EVENT_BUS_ERROR | Bus error detected (START/STOP at illegal position) |
void* I2C0(void);
void* I2C1(void);
void *
, 指向 I2C 实例的句柄int32_t I2C_Initialize(void* res, CSK_I2C_SignalEvent_t cb_event, void* workspace);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C实例句柄 |
cb_event | CSK_I2C_SignalEvent_t | 事件回调函数 |
workspace | void * | 固定传入 NULL |
int32_t I2C_Uninitialize(void* res);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C 实例句柄 |
int32_t I2C_PowerControl(void* res, CSK_POWER_STATE state);
int32_t
, CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C 实例句柄 |
state | CSK_POWER_STATE | 使能状态 CSK_POWER_OFF:失能状态 CSK_POWER_LOW:低功耗状态 CSK_POWER_FULL:全功能状态 |
int32_t I2C_Control(void* res, uint32_t control, uint32_t arg0);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C 实例句柄 |
control | uint32_t | 配置参数 |
arg | uint32_t | 可选参数 |
int32_t I2C_MasterTransmit(void* res, uint32_t addr, const uint8_t* data, uint32_t num,
bool xfer_pending);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C 实例句柄 |
addr | uint32_t | I2C 从机地址 |
data | uint8_t * | 指向发送缓冲区的指针 |
num | uint32_t | 发送数据的大小 |
xfer_pending | bool | 是否发送 Stop condition 0:发送 1:不发送 |
int32_t I2C_MasterReceive(void* res, uint32_t addr, uint8_t* data, uint32_t num,
bool xfer_pending);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C 实例句柄 |
addr | uint32_t | I2C 从机地址 |
data | uint8_t * | 指向接收缓冲区的指针 |
num | uint32_t | 接收数据的大小 |
xfer_pending | bool | 是否发送 Stop condition 0:发送 1:不发送 |
int32_t I2C_SlaveTransmit(void* res, const uint8_t* data, uint32_t num);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C 实例句柄 |
data | uint8_t * | 指向发送缓冲区的指针 |
num | uint32_t | 发送数据的大小 |
int32_t I2C_SlaveReceive(void* res, uint8_t* data, uint32_t num);
int32_t
,CSK_DRIVER_OK
表示成功,失败返回错误码参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C 实例句柄 |
data | uint8_t * | 指向接收缓冲区的指针 |
num | uint32_t | 接收数据的大小 |
int32_t I2C_GetDataCount(void* res);
int32_t
,表示传输完成的数据个数参数名 | 类型 | 说明 |
---|---|---|
res | void * | I2C 实例句柄 |
本小节在 CSK6012-NanoKit 开发板上实现 I2C0 为主机,I2C1 为从机,进行数据的收发。
I2C0(GPIO_A_10, GPIO_A_11)
作为主设备(master)I2C1(GPIO_A_12, GPIO_A_13)
作为从设备(slave)使用杜邦线将i2c0(GPIO_A_10, GPIO_A_11)
和i2c1(GPIO_A_12, GPIO_A_13)
连接,如下图示:
**Tip:**通常 I2C 通讯 SCL 和 SDA 之间都需要接上拉电阻(大小由速度和容性负载决定一般在 3.3K-10K 之间)以保证数据的稳定性,减少干扰,如下图示:
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <shell.h>
#include "IOMuxManager.h"
#include "Driver_I2C.h"
#include "lisa_log.h"
#include "lisa_typedef.h"
#include "lisa_thread.h"
#include "lisa_mem.h"
#include "event_groups.h"
#define I2C0_GPIO_SCL_PIN (10)
#define I2C0_GPIO_SDA_PIN (11)
#define I2C1_GPIO_SCL_PIN (13)
#define I2C1_GPIO_SDA_PIN (12)
#define I2C1_SLAVE_ADDRESS (0x50)
#define I2C_TAG "i2c_demo"
static bool g_i2c_testing = false;
static void *g_i2c0_handle = NULL;
static void *g_i2c1_handle = NULL;
static EventGroupHandle_t g_event_group = NULL;
static void i2c0_demo_evt(uint32_t event, void *workspace)
{
BaseType_t prio = pdFALSE;
xEventGroupSetBitsFromISR(g_event_group, event, &prio);
portYIELD_FROM_ISR(prio);
}
static void i2c1_demo_evt(uint32_t event, void *workspace)
{
BaseType_t prio = pdFALSE;
xEventGroupSetBitsFromISR(g_event_group, event, &prio);
portYIELD_FROM_ISR(prio);
}
void i2c0_demo_init()
{
///初始化为master
if (g_i2c0_handle == NULL)
{
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, I2C0_GPIO_SCL_PIN, CSK_IOMUX_FUNC_ALTER8);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, I2C0_GPIO_SDA_PIN, CSK_IOMUX_FUNC_ALTER8);
g_i2c0_handle = I2C0();
I2C_Initialize(g_i2c0_handle, i2c0_demo_evt, g_i2c0_handle);
I2C_PowerControl(g_i2c0_handle, CSK_POWER_FULL);
I2C_Control(g_i2c0_handle, CSK_I2C_TRANSMIT_MODE, 0);///0:中断模式,1:DMA模式
I2C_Control(g_i2c0_handle, CSK_I2C_BUS_SPEED, CSK_I2C_BUS_SPEED_STANDARD);
I2C_Control(g_i2c0_handle, CSK_I2C_BUS_CLEAR, 0);
}
return;
}
void i2c1_demo_init()
{
///初始化为slave
if(g_i2c1_handle == NULL)
{
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, I2C1_GPIO_SCL_PIN, CSK_IOMUX_FUNC_ALTER9);
IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, I2C1_GPIO_SDA_PIN, CSK_IOMUX_FUNC_ALTER9);
g_i2c1_handle = I2C1();
I2C_Initialize(g_i2c1_handle, i2c1_demo_evt, g_i2c1_handle);
I2C_PowerControl(g_i2c1_handle, CSK_POWER_FULL);
I2C_Control(g_i2c1_handle, CSK_I2C_TRANSMIT_MODE, 0);
I2C_Control(g_i2c1_handle, CSK_I2C_OWN_ADDRESS, I2C1_SLAVE_ADDRESS);//设置从机地址
}
return;
}
static void _handle_i2c_demo_start(void *arg)
{
uint8_t master_transmit_data[10] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
uint8_t slave_transmit_data[10] = {0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};
uint8_t read_p[10] = {0};
i2c0_demo_init();
i2c1_demo_init();
lisa_thread_mdelay(1000);
while (true)
{
///主机发送,从机接收
LISA_LOGD(I2C_TAG, "master send slave recv");
//1.发送数据
I2C_MasterTransmit(g_i2c0_handle, I2C1_SLAVE_ADDRESS, master_transmit_data, 10, 0);
//2.等待发送完成
xEventGroupWaitBits(g_event_group, CSK_I2C_EVENT_TRANSFER_DONE, pdTRUE, pdTRUE, portMAX_DELAY);
//3.等待从机接收到addr hit
xEventGroupWaitBits(g_event_group, CSK_I2C_EVENT_SLAVE_RECEIVE, pdTRUE, pdTRUE, portMAX_DELAY);
//4.接收数据
I2C_SlaveReceive(g_i2c1_handle, read_p, 10);
//5.等待接收完成
xEventGroupWaitBits(g_event_group, CSK_I2C_EVENT_TRANSFER_DONE, pdTRUE, pdTRUE, portMAX_DELAY);
for(int i = 0; i < 10; i++)
{
LISA_LOGD(I2C_TAG, "slave recv data = 0x%02x", read_p[i]);
}
xEventGroupClearBits(g_event_group, 0x1FF);
///切换为从机发送,主机接收
memset(read_p, 0, 10);
I2C_Control(g_i2c0_handle, CSK_I2C_TRANSMIT_MODE, 1);
I2C_Control(g_i2c1_handle, CSK_I2C_TRANSMIT_MODE, 1);
lisa_thread_mdelay(1000);
LISA_LOGD(I2C_TAG, "slave send master recv");
//1.发送读请求
I2C_MasterReceive(g_i2c0_handle, I2C1_SLAVE_ADDRESS, read_p, 10, 0);
//2.等待从机接收到addr hit
xEventGroupWaitBits(g_event_group, CSK_I2C_EVENT_SLAVE_TRANSMIT, pdTRUE, pdTRUE, portMAX_DELAY);
I2C_SlaveTransmit(g_i2c1_handle, slave_transmit_data, 10);
//3.等待接收完成
xEventGroupWaitBits(g_event_group, CSK_I2C_EVENT_TRANSFER_DONE, pdTRUE, pdTRUE, portMAX_DELAY);
for(int i = 0; i < 10; i++)
{
LISA_LOGD(I2C_TAG, "master recv data = 0x%02x", read_p[i]);
}
xEventGroupClearBits(g_event_group, 0x1FF);
memset(read_p, 0, 10);
I2C_Control(g_i2c0_handle, CSK_I2C_TRANSMIT_MODE, 0);
I2C_Control(g_i2c1_handle, CSK_I2C_TRANSMIT_MODE, 0);
lisa_thread_mdelay(1000);
}
}
void shell_i2c_demo_test()
{
SHELL_ITEM_EXPORT("demo.i2c", shell_i2c_demo_test, "i2c demo test");
LISA_LOGD(I2C_TAG, "i2c_demo_test start");
if (g_i2c_testing) {
LISA_LOGD(I2C_TAG, "i2c_demo_test is started");
return;
}
g_i2c_testing = true;
g_event_group = xEventGroupCreate();
lisa_thread_attr_t thread_attr;
thread_attr.name = "i2c demo";
thread_attr.stack_size = 2048;
thread_attr.priority = LISA_OS_PRIORITY_NORMAL;
lisa_thread_t *i2c_thread = lisa_thread_create(&thread_attr, _handle_i2c_demo_start, NULL);
if (i2c_thread == NULL)
{
LISA_LOGE(I2C_TAG, "create i2c demo thread error");
}
}
evs_err_t evs_twdt_init(void);
evs_err_t
evs_err_t evs_twdt_deinit(void);
接口说明:该接口用于逆初始化软件看门狗模块
返回值:evs_err_t
evs_err_t evs_twdt_add(TaskHandle_t handle, uint32_t timeout_ms);
接口说明:该接口用于向软件看门狗添加任务监控
返回值:evs_err_t
参数名 | 类型 | 说明 |
---|---|---|
handle | TaskHandle_t | 需要监控的任务句柄 |
timeout_ms | uint32_t | 任务超时时间 |
evs_err_t evs_twdt_add_and_feed(TaskHandle_t handle, uint32_t tm_interval, uint32_t timeout_ms);
接口说明:该接口用于向软件看门狗添加任务监控并喂狗。若已添加任务, 则不会重复添加,只喂狗
返回值:evs_err_t
参数名 | 类型 | 说明 |
---|---|---|
handle | TaskHandle_t | 需要监控的任务句柄 |
tm_interval | uint32_t | 最小喂狗间隔,单位毫秒 |
timeout_ms | uint32_t | 任务超时时间,单位毫秒 |
evs_err_t evs_twdt_feed(uint32_t tm_interval);
接口说明:该接口用于向软件看门狗喂狗,喂狗任务为当前调用接口栈空间
返回值:evs_err_t
参数名 | 类型 | 说明 |
---|---|---|
tm_interval | uint32_t | 最小喂狗间隔,单位毫秒 |
evs_err_t evs_twdt_delete(TaskHandle_t handle);
接口说明:该接口用于删除之前添加在软件看门狗中监控的任务
返回值:evs_err_t
参数名 | 类型 | 说明 |
---|---|---|
handle | TaskHandle_t | 任务句柄 |
2.1 SDK 启动后调用初始化接口,软件看门狗模块会自动监控 Tmr Svc 任务,时间为 6s(初始化接口 SDK 已经调用了)
2.2 evs_event 加入监控: evs_event 任务启动后,会自动将自身添加进监控任务(SDK 已经支持,不需要开发者额外处理)
2.3 使用 evs_event 处理业务(开发者只需将需要监控的业务使用 evs_event 处理即可,参考文档 EVS_EVENT 任务部分)
RTC(Real Time Clock)实时时钟是应用开发中常用的外设。
int settimeofday2(const struct timeval *tv, const void *tz);
接口说明:该接口用于设置时间
返回值:int
0:成功 其他:失败
参数名 | 类型 | 说明 |
---|---|---|
tv | timeval * | timeval结构体指针 |
tz | void * | 时区,目前不支持,传NULL即可 |
int gettimeofday2(struct timeval *tv, void *tz);
接口说明:该接口用于获取时间
返回值:int
0:成功 其他:失败
参数名 | 类型 | 说明 |
---|---|---|
tv | timeval * | timeval结构体指针 |
tz | void * | 时区,目前不支持 |
struct timeval tv = {
.tv_sec = 1664596800L, // 2022-10-01 12:00:00
.tv_usec = 0,
};
// 设置时间
settimeofday2(&tv, NULL);
struct timeval tv2;
// 获取时间
gettimeofday2(&tv2, NULL);
typedef void (*listen_key_cb)(uint8_t key, uint8_t event);
int listen_key_init(listen_key_cb *cb);
接口说明:该接口用于初始化按键模块并设置按键回调
返回值:int
,返回0代表初始化成功
参数名 | 类型 | 说明 |
---|---|---|
cb | listen_key_cb | 按键事件回调 |
listen_key_cb:
参数名 | 类型 | 说明 |
---|---|---|
key | uint8_t | 按键的key |
event | uint8_t | 按键的event,有pressed和released |
int listen_key_deinit(void);
int
,返回0代表初始化成功static void client_key_cb(uint8_t key, uint8_t event)
{
if (event == BTN_EVT_PRESSED) {
printk("key %d pressed\n", key);
} else if (event == BTN_EVT_RELEASED) {
printk("key %d released\n", key);
}
}
// key init
listen_key_init(client_key_cb);