一、任务介绍
MAX32655FTHR 是一款快速开发平台,可帮助工程师使用MAX32655 Arm© Cortex®-M4F和Bluetooth® 5.2低功耗(LE)快速实施超低功耗无线解决方案。该电路板还包括MAX20303 PMIC以实现电池和电源管理。0.9 x 2.6英寸小尺寸双排接头与Adafruit Feather Wing外设扩展板兼容。该电路板包括各种外设,如数字麦克风、低功耗立体声音频编解码器、128MB QSPI闪存、micro SD卡连接器、RGB指示器LED和按钮。
本次实现任务1:使用MAX32655FTHR板卡搭配任意彩色LCD屏幕,移植LVGL,设计一个显示两个ADC通道数值的app。
二、硬件介绍
2.1、MAX32655FTHR板卡特点:
- MAX32655微控制器
- ARM Cortex-M4F,100MHz
- 32位RISC-V协处理器,可减轻时序关键型蓝牙处理负荷
- 512KB闪存
- 128KB SRAM
- 16KB缓存
- 蓝牙5.2 LE无线电
- 带电量计的MAX20303可穿戴PMIC
- 通过USB充电
- 用于Arm Cortex-M4F的板载DAPLink调试和编程接口
- 试验板兼容接头
- Micro USB连接器
- Micro SD卡连接器
- 集成外设
- RGB指示灯LED
- 用户按钮
- 低功耗立体声音频编解码器
- 数字麦克风
- SWD调试器
- 虚拟UART控制台

板卡引脚图:



2.2扩展板
针对本次任务,我设计了基于MAX32655FTHR开发板的扩展板,板载摇杆XY双轴,用于ADC采样。板载一个2.4寸LCD屏,分辨率为320*240。另外还扩展了一个arduino接口,可以用于外接其他设备。这里设计一个瑕疵就是ADC采样基准电压只能选择VDD/2或者内部1.22V,达不到3.3V,导致摇杆的有效范围很小。
扩展板电路图如下:

PCB设计:

实物图:

三、软件开发
3.1、KEIL开发环境配置
本次软件使用keil开发环境,首先下载MAX32655的device pack包安装。

安装之后就可以在keil中开发了。

勾选设备的开发库。

3.2、任务应用流程图
接下来就是应用开发。首先就是初始化外设和lvgl移植,然后就是lvgl应用界面开发。软件流程图如下:

主函数代码如下,初始化及任务循环。
int main()
{
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000U);
// Enable GPIO
MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_GPIO0);
MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_GPIO1);
MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_GPIO2);
if (MXC_GPIO_Config(&led_pin[0]) != E_NO_ERROR) {
}
if (MXC_GPIO_Config(&led_pin[1]) != E_NO_ERROR) {
}
if (MXC_GPIO_Config(&led_pin[2]) != E_NO_ERROR) {
}
if (MXC_UART_Init(ConsoleUart, 115200, MXC_UART_IBRO_CLK) != E_NO_ERROR) {
while (1);
}
printf("hello max32655\r\n");
/* Initialize ADC */
if (MXC_ADC_Init() != E_NO_ERROR) {
while (1);
}
/* Set up LIMIT0 to monitor high and low trip points */
MXC_ADC->ctrl |= ((uint32_t)(0x1UL << 4));
MXC_ADC_SetMonitorChannel(MXC_ADC_MONITOR_0, MXC_ADC_CH_0);
MXC_ADC_SetMonitorHighThreshold(MXC_ADC_MONITOR_0, 0x300);
MXC_ADC_SetMonitorLowThreshold(MXC_ADC_MONITOR_0, 0x25);
MXC_ADC_EnableMonitor(MXC_ADC_MONITOR_0);
#ifdef USE_INTERRUPTS
NVIC_EnableIRQ(ADC_IRQn);
#endif
lv_init();
lv_port_disp_init();
setup_ui(&guider_ui);
events_init(&guider_ui);
custom_init(&guider_ui);
while(1)
{
lv_task_handler();
}
return 0;
}
再就是ADC采样和lvgl显示,其中ADC采样流程:

static int16_t adc_chart1[CHART_POINTS] = {0};
static int16_t adc_chart2[CHART_POINTS] = {0};
uint16_t adc_val1,adc_val2;
// 更新数值的函数
void update_label_value(lv_obj_t * label, int value)
{
static char buffer[32];
snprintf(buffer, sizeof(buffer), "%d mV", value);
lv_label_set_text(label, buffer);
}
void record_chart_timer_cb(lv_timer_t * t)
{
lv_obj_t * obj = t->user_data;
lv_chart_series_t * ser = lv_chart_get_series_next(obj, NULL);
lv_coord_t * ser_array1 = lv_chart_get_y_array(obj, ser);
ser = lv_chart_get_series_next(obj, ser);
lv_coord_t * ser_array2 = lv_chart_get_y_array(obj, ser);
for(int i = 0; i < (CHART_POINTS - 1); i++)
{
adc_chart1[i] = adc_chart1[i+1];
ser_array1[i] = adc_chart1[i];
adc_chart2[i] = adc_chart2[i+1];
ser_array2[i] = adc_chart2[i];
}
adc_val1 = MXC_ADC_StartConversion(MXC_ADC_CH_0)*1650/1024;
adc_chart1[CHART_POINTS - 1] = adc_val1;
update_label_value(guider_ui.record_label_4, adc_val1);
adc_val2 = MXC_ADC_StartConversion(MXC_ADC_CH_1)*1650/1024;
adc_chart2[CHART_POINTS - 1] = adc_val2;
update_label_value(guider_ui.record_label_2, adc_val2);
ser_array1[CHART_POINTS - 1] = adc_chart1[CHART_POINTS - 1];
ser_array2[CHART_POINTS - 1] = adc_chart2[CHART_POINTS - 1];
lv_chart_refresh(obj);
}
3.3、lvgl的显示界面开发
lvgl使用的是V8.4.10版本,使用GUIDER设计界面:显示2组标签ADC数值标签和图表控件。

在界面启动时,定义并初始化一个定时器任务。用于ADC采样和显示。

最终软件编译下载烧写到开发板上实现的效果:

3.4、项目开发中一些问题说明
首先就是KEIL编译maxin的SDK库时需要修改一些地方,否则编译不通过。第一个修改nvic_table.c文件。

第二个文件是sys_me17.c文件内容。


其次就是lcd驱动实现,其中GPIO引脚初始化时需要设置MXC_GPIO_VSSEL_VDDIOH属性。
mxc_gpio_cfg_t tft_gpio_pin[] = {
{MXC_GPIO1, MXC_GPIO_PIN_6, MXC_GPIO_FUNC_OUT, MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH}, //DC
{MXC_GPIO1, MXC_GPIO_PIN_7, MXC_GPIO_FUNC_OUT, MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH}, //BACKLIGHT
{MXC_GPIO1, MXC_GPIO_PIN_8, MXC_GPIO_FUNC_OUT, MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH}, //RESET
{MXC_GPIO1, MXC_GPIO_PIN_9, MXC_GPIO_FUNC_OUT, MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH}, //
};
void tft_spi_init(void)
{
int master = 1;
int quadMode = 0;
int numSlaves = 1;
int ssPol = 0;
unsigned int tft_hz = 30000000;
mxc_spi_pins_t tft_pins;
tft_pins.clock = true;
tft_pins.ss0 = (SPI_CS_SEL == 0); ///< Slave select pin 0
tft_pins.ss1 = (SPI_CS_SEL == 1); ///< Slave select pin 1
tft_pins.ss2 = (SPI_CS_SEL == 2); ///< Slave select pin 2
tft_pins.miso = true; ///< miso pin
tft_pins.mosi = true; ///< mosi pin
tft_pins.sdio2 = false; ///< SDIO2 pin
tft_pins.sdio3 = false; ///< SDIO3 pin
tft_pins.vddioh = true; ///< VDDIOHn (3.3V) select for display
MXC_SPI_Init(TFT_SPI, master, quadMode, numSlaves, ssPol, tft_hz, tft_pins);
MXC_SPI_SetDataSize(TFT_SPI, 8);
MXC_SPI_SetWidth(TFT_SPI, SPI_WIDTH_STANDARD);
}
static void spi_transmit(mxc_spi_regs_t* spi, void* datain, unsigned int count)
{
mxc_spi_req_t request = {
spi, // spi
0, // ssIdx
1, // ssDeassert
(uint8_t*) datain, // txData
NULL, // rxData
count, // txCnt
0 // rxCnt
};
MXC_SPI_MasterTransaction(&request);
}
int LCD_WriteReg16(uint16_t Reg, uint8_t *pData, uint16_t Length)
{
MXC_GPIO_OutClr(tft_gpio_pin[0].port, tft_gpio_pin[0].mask);
spi_transmit(TFT_SPI,&Reg, 1);
if(Length)
{
MXC_GPIO_OutSet(tft_gpio_pin[0].port, tft_gpio_pin[0].mask);
spi_transmit(TFT_SPI,pData, Length);
}
return 0;
}
int LCD_ReadReg16(uint16_t Reg, uint8_t *pData, uint16_t Length)
{
return 0;
}
int LCD_SendData(uint8_t *pData, uint32_t Length)
{
if(Length)
{
MXC_GPIO_OutSet(tft_gpio_pin[0].port, tft_gpio_pin[0].mask);
spi_transmit(TFT_SPI,pData, Length);
}
return 0;
}
再就是需要安装lvgl的keil包。直接勾选lvgl代码到工程中。

四、项目总结
非常高兴能参加这个活动。本次活动主要学习了max32655的keil开发环境的搭建和应用,以及max32655的GPIO,ADC,SPI,UART等外设的应用,以及驱动LCD屏并实现LVGL的移植和应用界面开发。