感谢论坛和极海提供的APM32F411-TINY开发板,通过两周的学习,对F411芯片的基础外设做了简单的测试。
1、RTOS
本测试使用RTX操作系统,ARM针对M家族芯片做好了适配,选择对应的文件即可完成操作系统的添加。
RTX的启动相对较为简单,代码如下:
osKernelInitialize(); // Initialize CMSIS-RTOS
thread_obj_init();
thread_init();
if (osKernelGetState() == osKernelReady)
{
osKernelStart(); // Start thread execution
}
2、串口控制台
为方便人机交互,本测试工程添加了一组控制台程序,使用方法类似SHELL,可从串口输入命令来执行内部函数。控制台是一个独立的任务,串口使用板载调试器的串口进行连接,效果如下:打开串口输入SHELL -H可查看可用命令
3、DMA 测试
F411用有两组DMA模块,可以极大释放CPU占用率,提高系统运行速度。为了方便使用,本次测试封装了一组DMA接口:包含以下功能:
/*******************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] APP DMA type
*******************************************************************************/
typedef struct
{
DMA_T *DMAx; // DMA 模块
DMA_Stream_T *stream; // DMA 数据流
uint16_t ch_num; // DMA 通道编号
uint16_t trig_src; // DMA 触发源
IRQn_Type irqn; // 中断号
} app_dma_type;
#ifdef IN_DMA_MOUDLE
#define dma_stream_make(name, dmax, ch, src) \
const app_dma_type name = { \
.DMAx = dmax, \
.stream = dmax##_Stream##ch, \
.ch_num = ch, \
.trig_src = src, \
.irqn = dmax##_STR##ch##_IRQn}
#else
#define dma_stream_make(name, dmax, ch, src) \
extern const app_dma_type name
#endif
/*******************************************************************************
* @brief APP DMA CONFIG
*******************************************************************************/
dma_stream_make(DMA_U01_RX, DMA2, 2, 4);
dma_stream_make(DMA_U01_TX, DMA2, 7, 4);
dma_stream_make(DMA_U04_RX, DMA1, 2, 4);
dma_stream_make(DMA_U04_TX, DMA1, 4, 4);
dma_stream_make(DMA_U06_RX, DMA2, 1, 5);
dma_stream_make(DMA_U06_TX, DMA2, 6, 5);
dma_stream_make(DMA_ADC, DMA2, 0, 0);
/*******************************************************************************
* @brief 中断回调注册
*******************************************************************************/
typedef struct
{
void (*stream10)(void);
void (*stream11)(void);
void (*stream12)(void);
void (*stream13)(void);
void (*stream14)(void);
void (*stream15)(void);
void (*stream16)(void);
void (*stream17)(void);
void (*stream20)(void);
void (*stream21)(void);
void (*stream22)(void);
void (*stream23)(void);
void (*stream24)(void);
void (*stream25)(void);
void (*stream26)(void);
void (*stream27)(void);
} dma_it_type;
extern dma_it_type dma_it;
/*******************************************************************************
* @brief APP DMA API
*******************************************************************************/
void dma_nvic_set(const app_dma_type *dmax, uint32_t irq_en, void (*callback)(void));
/*******************************************************************************
* @brief 配置
*******************************************************************************/
typedef struct
{
uint8_t mem_to_periph;
uint8_t cycle_mode;
uint8_t mem_inc, periph_inc;
uint16_t data_len;
DMA_PRIORITY_T prio;
void *mem;
volatile void *periph;
} dma_stream_cfg_type;
void dma_stream_config(const app_dma_type *dmax, dma_stream_cfg_type *cfg);
/*******************************************************************************
* @brief 获取传输完成标志
* \param[in] dma
* \retval: 0-No 1-Yes
*******************************************************************************/
__STATIC_INLINE uint32_t dma_comp_flag_get(const app_dma_type *dmax)
{
int ch_num = dmax->ch_num;
uint32_t bit_pos = ((ch_num % 4) / 2) * 16 + (ch_num % 2) * 6 + 5;
return ((&(dmax->DMAx->LINTSTS))[ch_num / 4] >> bit_pos) & 1;
}
/*******************************************************************************
* @brief 清除传输完成标志
* \param[in] dma
* \retval: 0-No 1-Yes
*******************************************************************************/
__STATIC_INLINE void dma_comp_flag_clr(const app_dma_type *dmax)
{
int ch_num = dmax->ch_num;
uint32_t bit_pos = ((ch_num % 4) / 2) * 16 + (ch_num % 2) * 6 + 5;
(&(dmax->DMAx->LIFCLR))[ch_num / 4] = 0x3DUL << bit_pos;
}
/*******************************************************************************
* @brief 库接口映射
* \param[in] dma
* \retval: 0-No 1-Yes
*******************************************************************************/
/* 反初始化 */
#define dma_stream_deinit(dmax) DMA_Reset((dmax)->stream)
/* 判断是否已使能DMA数据流 */
#define is_dma_stream_enable(dmax) (dmax)->stream->SCFG_B.EN
/* 使能DMA数据流 */
#define dma_stream_enable(dmax) \
dma_comp_flag_clr(dmax); \
DMA_Enable((dmax)->stream)
/* 禁能DMA数据流 */
#define dma_stream_disable(dmax) DMA_Disable((dmax)->stream)
/* 设置DMA数据流RAM地址 */
#define dma_stream_set_mem_addr(dmax, addr) (dmax)->stream->M0ADDR = (addr)
/* 设置DMA数据流外设地址 */
#define dma_stream_set_periph_addr(dmax, addr) (dmax)->stream->PADDR = (addr)
/* 设置DMA数据流数据长度 */
#define dma_stream_set_data_len(dmax, len) (dmax)->stream->NDATA = (len)
/* 获取DMA数据流剩余传输长度 */
#define dma_stream_get_data_len(dmax) (dmax)->stream->NDATA
/* 使能数据流传输完成中断 */
#define dma_stream_complete_isr_enable(dmax) (dmax)->stream->SCFG_B.TXCIEN = 1
封装后,DMA的使用更加方便,具体的使用参加控制台串口,该串口收发数据使用了DMA优化。
4、MODBUS测试
本程序开通了4路MODBUS接口,分别使用UART2/3/4/6,其中U3/4做主站,U2/6做从站。
// master config
qc03_Init(QC_MODE_MASTER, 115200, MB_PAR_NONE);
mb.qc03.os_event_send = mb3_os_event_send;
qc04_Init(QC_MODE_MASTER, 19200, MB_PAR_NONE);
mb.qc04.os_event_send = mb3_os_event_send;
mcmd.id = 1;
mcmd.wdat = &mb_input[0].uval;
mcmd.rdat = &mb_input[0].uval;
mcmd.wa = 0;
mcmd.wn = 96;
mcmd.ra = 0x1800;
mcmd.rn = 1;
mcmd.callback = qc_callback;
mcmd.attr = QC_MB_ATTR_HOLD_MW;
mqc_stc_cmd_req(&mb.qc03, 0, &mcmd);
mqc_stc_cmd_req(&mb.qc04, 0, &mcmd);
mcmd.wdat = &mb_input[0].uval;
mcmd.wa = 96;
mcmd.wn = 96;
mqc_stc_cmd_req(&mb.qc03, 1, &mcmd);
mqc_stc_cmd_req(&mb.qc04, 0, &mcmd);
// slave config
qc02_Init(QC_MODE_SLAVE, 115200, MB_PAR_NONE);
mb.qc02.os_event_send = mb2_os_event_send;
qc06_Init(QC_MODE_SLAVE, 19200, MB_PAR_NONE);
mb.qc06.os_event_send = mb8_os_event_send;
mcmd.id = 1;
mcmd.wdat = &mb_input[0].uval;
mcmd.rdat = &mb_input[0].uval;
mcmd.wa = 16;
mcmd.wn = 16;
mcmd.ra = 0;
mcmd.rn = 8;
mcmd.callback = qc_callback;
mcmd.attr = QC_MB_ATTR_HOLD_MW;
mqc_stc_cmd_req(&mb.qc02, 0, &mcmd);
mqc_stc_cmd_req(&mb.qc02, 1, &mcmd);
mqc_stc_cmd_req(&mb.qc06, 0, &mcmd);
mqc_stc_cmd_req(&mb.qc06, 1, &mcmd);
连接U4和U6可以进行通信,调试状态测试结果如下
5、SPI测试
SPI接口外接SPI-FLASH进行测试:
SPI 配置如下
SPI_Config_T cfg;
intx_alloc();
// 开启时钟
intx_disable();
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SPI1);
RCM_EnableAPB2PeriphReset(RCM_APB2_PERIPH_SPI1);
RCM_DisableAPB2PeriphReset(RCM_APB2_PERIPH_SPI1);
intx_enable();
// SPI 配置
cfg.direction = SPI_DIRECTION_2LINES_FULLDUPLEX;
cfg.baudrateDiv = SPI_BAUDRATE_DIV_16;
cfg.mode = SPI_MODE_MASTER;
cfg.length = SPI_DATA_LENGTH_8B;
cfg.firstBit = SPI_FIRSTBIT_MSB;
cfg.nss = SPI_NSS_SOFT;
cfg.polarity = SPI_CLKPOL_LOW;
cfg.phase = SPI_CLKPHA_1EDGE;
cfg.crcPolynomial = 0;
SPI_Config(NOR_SPI, &cfg);
NOR_SPI->CTRL1_B.SPIEN = 1;
nor_spi_cs(0);
nor_spi_rb();
nor_spi_cs(1);
b_io_q_mode = 0;
在控制台输入FLASH测试命令:nor check 4 对FLASH写入4MB数据并读取验证,如下图所示:
下面附上测试代码,有兴趣的小伙伴可下载研究交流:
APM32F411-TINY.rar
(8.77 MB)
|
|