UI相关应用
📎 原始文档:https://www.kdocs.cn/l/ckhf4dZtUTjJ UI相关应用
- 128*64点阵液晶模块 (黑白屏)
程序配置
- 配置UI相关配置 宏配置
//*********************************************************************************//
// UI 配置 //
//*********************************************************************************//
#define TCFG_UI_ENABLE ENABLE_THIS_MOUDLE //UI总开关
#define CONFIG_UI_STYLE STYLE_JL_SOUNDBOX
// #define CONFIG_UI_STYLE STYLE_UI_SIMPLE //这是309 sdk ui 风格 需要再开启TCFG_SIMPLE_LCD_ENABLE
// #define TCFG_UI_LED7_ENABLE ENABLE_THIS_MOUDLE //UI使用LED7显示
// #define TCFG_UI_LCD_SEG3X9_ENABLE ENABLE_THIS_MOUDLE //UI使用LCD段码屏显示
// #define TCFG_LCD_ST7735S_ENABLE ENABLE_THIS_MOUDLE
// #define TCFG_LCD_ST7789VW_ENABLE ENABLE_THIS_MOUDLE
#define TCFG_LRC_LYRICS_ENABLE ENABLE_THIS_MOUDLE //歌词显示
#define TCFG_LCD_OLED_ENABLE ENABLE_THIS_MOUDLE
#define TCFG_SPI_LCD_ENABLE ENABLE_THIS_MOUDLE //spi lcd开关
#define TCFG_SIMPLE_LCD_ENABLE DISABLE_THIS_MOUDLE//去ui 框架的驱动开关 开启请关闭了TCFG_SPI_LCD_ENABLE
#define TCFG_TFT_LCD_DEV_SPI_HW_NUM 1// 1: SPI1 2: SPI2 配置lcd选择的spi口
#define LCD_SPI_INTERRUPT_ENABLE 0//默认开启 需要主动关闭
#define ALL_KEY_EVENT_CLICK_ONLY 1 //是否全部按键只响应单击事件
IO配置
#if (TCFG_SPI_LCD_ENABLE || TCFG_SIMPLE_LCD_ENABLE)
LCD_SPI_PLATFORM_DATA_BEGIN(lcd_spi_data)
#if TCFG_LCD_OLED_ENABLE
.pin_reset = IO_PORTC_01,
.pin_cs = IO_PORTC_03,
.pin_rs = IO_PORTC_02,
.pin_bl = IO_PORTC_00,
#else
.pin_reset = -1,
.pin_cs = IO_PORTC_03,
.pin_rs = IO_PORTC_02,
.pin_bl = IO_PORTC_01,
#endif
#if (TCFG_TFT_LCD_DEV_SPI_HW_NUM == 1)
.spi_cfg = SPI1,
.spi_pdata = &spi1_p_data,
#elif (TCFG_TFT_LCD_DEV_SPI_HW_NUM == 2)
.spi_cfg = SPI2,
.spi_pdata = &spi2_p_data,
#endif
LED7_PLATFORM_DATA_END()
const struct ui_devices_cfg ui_cfg_data = {
.type = TFT_LCD,
.private_data = (void *)&lcd_spi_data,
};
#endif
- 液晶屏初始化代码 根据使用的屏的驱动自行修改
//初始化SSD1306
static void SPI_OLED_Init(void)
- 不同规格液晶屏大小修改
#define SCR_X 0 ///屏幕起始点X的偏移
#define SCR_Y 0 ///屏幕起始点Y的偏移
#define SCR_W 128 ///刷新屏幕的宽度,与LCD_W 一致
#define SCR_H 64 ///刷新屏幕的高度,与LCD_H 一致
#define LCD_W 128
#define LCD_H 64
#define LCD_BLOCK_W 128 //显存buf的大小设定
#define LCD_BLOCK_H 64 //显存buf的大小设定
#define BUF_NUM 2 ///buf 数量
DEMO程序
硬件接口:(一组SPI口+3个普通GPIO)如下
| 主控接口1 | LCD屏接口 |
|---|---|
| LCD_DATA | SDA |
| LCD_CLK | SCK |
| LCD_A0 | RS |
| LCD_RES | RST |
| LCD_CS | CS |
程序:
AC695N_soundbox_sdk_release_3.1.0 OLEDDEMO:
https://gitlab.zh-jieli.com/soundbox/novisualization/ac695n_soundbox_sdk/-/tree/feature_310_OLED
【金山文档】 jl701n_soundbox_release_v1.3.0_OLED
【金山文档】 jl701n_soundbox_release_v1.4.1_OLED
demo_701142_OLED_lrc.zip(文本单字滚动)
demo_701_142_oled_pixscoll.zip(实现文字像素点滚动)
feature_695_310_OLED_pixscoll.zip(实现文字像素点滚动)
点阵屏歌词字库相关(蓝牙歌词,普通歌词):
点阵屏歌词字库相关(蓝牙歌词,普通歌词).otl
ac695n_soundbox_sdk_310_纯歌词文件输出.7z( 不跑内置UI系统,可以通过外发做显示,输出格式为UTF8)
UNICODE字库显示(可以同时显示中文韩文日文等):
字模提取工具说明
字模提取工具说明.otl
2. 音箱可视化彩屏 音箱可视化彩屏-入门到进阶开发指导.otl(持续更新中)
3. HUB75/IO屏
- ic选型
| 屏幕类型 | io互推单色屏 | HUB75单色屏 | HUB75彩屏 |
|---|---|---|---|
| ic类型 | AD101C | AD172A8 | AW302B |
| 屏像素 | 12*120 | 16x96 | 16x96 |
| 资料 | 硬件 | 硬件 | 硬件 |
| 仓库地址 | 代码地址 |
- HUB75屏调试
- 硬件资料 驱动ic:
HUB75驱动ic资料
单色原理图:
16X96 LED阵列标准原理图V1.0
12X72单色LED_V1.0.pdf
彩色原理图:
16X96 RGB_LED阵列标准原理图V1.0
原理图说明:- JIN1是接线座
- BR1电阻控制每一个输出的电流。Iout =18800/BR1 mA
- 原理图设计是逐行扫描,SM16208SC控制一行中的每一个灯,如需增加一行中的灯数量,增加SM16208SC,级联下去即可。
- SM5166PS控制行输出,如需增加行数,增加SM5166PS级联即可。
- U1作电平转换
- RGB效果相当于在单色灯的寄出上增加两个LED,行数不变,灯数增加,增加SM16208SC,增加数据SDI输入既可以。
- 单元亮灯的原理如下图
图源:https://www.sparkfun.com/news/2650
相关资料:
关于LED点阵屏单元板的通信接口——HUB75 - 哔哩哔哩
- 驱动说明
背景
- 屏幕驱动目前做的是32扫32行128列,没有做32扫64行128列。
- 驱动使用4线spi三data引脚与模块的R1 G1 B1连接

- 屏幕模块R1/G1/B1 R2/G2/B2共用同一个clk所以能实现32扫显示64行的效果
- 也是由于这个原因导致四线spi只能同时驱动1/64行不能实现2/64,如果需要实现2/64的显示需要6线并行输出的设备
大致流程:

编译
ac701n_soundbox_sdk-lvgl-led-20240106.7z
windows下使用Makefile编译
驱动代码
相关头文件:
led_drive.h、led_run.h、head.h
硬件引脚定义:
#define SPI_HW_NUM SPI2//可选择spi1-2
#define SPI_PI_CLK IO_PORTA_02//clk
//第一组io
#define SPI_0_PI_D0_R IO_PORTA_03//R
#define SPI_0_PI_D1_G IO_PORTA_04//G
#define SPI_0_PI_D1_B IO_PORTA_05//B
#define SPI_0_PI_D3_NULL IO_PORTG_05//无效引脚
//SM_5166
#define SM_5166_PORTA IO_PORTB_03
#define SM_5166_PORTB IO_PORTB_04
#define SM_5166_PORTC IO_PORTB_05
#define SM_5166_PORTD IO_PORTB_06
#define SM_5166_PORTE IO_PORTB_07
//SM_1620
#define SM_1620_LE_PORT IO_PORTG_03
#define SM_1620_OE_PORT IO_PORTG_04
屏幕、颜色相关配置:
#define SINGLE_WIDTH (128)//宽
#define SINGLE_HEIGHT (32)//高
#define SCAN_LIN (32)//N扫行
#define FRAME_BUFF_NUMBER (2)//帧缓存数
#define DEPTH_LEVEL (32)//颜色梯度 R(0-N) G(0-N) B(0-N) RGB565这里就要设置为32
初始化led驱动
void led_run_init(void);
void app_task_loop()
{
led_run_init();
...
}
数据更新接口
void led_display_one_frame(COLOUR_RGB rgb[SINGLE_HEIGHT][SINGLE_WIDTH]);
- 软件配置 参考程序是基于开源LVGLUI框架,最终输出数据使用RGB灯板驱动进行对接。
输出对接函数
LV_ATTRIBUTE_FAST_MEM static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
现在LVGL适配屏幕限制了只能RGB565输出。但是不用过于担心,程序中做了一次转换为RGB888格式。现在屏驱能适配到32个梯度即0x20=32。不会影响最终的输出精度。
修改HUB75灯板驱动大小
//修改HUB75灯板大小,以128*32灯板为例,只做初始化使用,方便在LVGL获取准确大小,不做最终输出函数。
#define SCR_X 0
#define SCR_Y 0
#define SCR_W 128
#define SCR_H 32
#define LCD_W 128
#define LCD_H 32
#define LCD_BLOCK_W 128
#if (defined(TCFG_SMART_VOICE_ENABLE) && (TCFG_SMART_VOICE_ENABLE == 1))
#define LCD_BLOCK_H 20
#else /*TCFG_SMART_VOICE_ENABLE == 0*/
#define LCD_BLOCK_H 32
#endif /*TCFG_SMART_VOICE_ENABLE*/
#define BUF_NUM 2
LVGL参考指南:
LVGL修改控件位置以及大小:
在void setup_scr_screen(lv_ui *ui)函数中,默认只做了一个页面,如有需要可以按照指南新增页面。
ui->screen = lv_obj_create(NULL);
lv_obj_set_size(ui->screen, 128, 32); //修改整个屏幕大小
//Write style for screen, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
lv_obj_set_style_bg_opa(ui->screen, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui->screen, lv_color_hex(0x000000), LV_PART_MAIN|LV_STATE_DEFAULT);
//Write codes screen_MUSIC_SRC
ui->screen_MUSIC_SRC = lv_label_create(ui->screen);
lv_label_set_text(ui->screen_MUSIC_SRC, "深圳市杰理微电子科技有限公司");
lv_label_set_long_mode(ui->screen_MUSIC_SRC, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_pos(ui->screen_MUSIC_SRC, 0, 0); //修改控件起始位置
lv_obj_set_size(ui->screen_MUSIC_SRC, 128, 16); //修改控件大小
支持功能:LED灯板只是一个显示器件,和程序对接好了之后,只用当作屏幕一样使用,所以LVGL能够使用的内容,如图片显示等都可以在这个程序中实现并显示。
LVGL修改文本控件内容:
注意:UI控件的操作要求只在UI线程中进行调用,在其他线程中直接调用有概率出现死机复位。
//按照程序示例在其他线程调用,并post出来消息事件,集中在UI线程中处理
void show_music_src(u8 *info)
{
strcpy(user_msg[MUSIC_SRC].info,info); //参数输入格式为UTF8格式。
lvgl_user_send_msg(MUSIC_SRC);
}
void show_music_now_time(u8 min,u8 sec)
{
u8 info[10];
sprintf(info,"%02d:%02d",min,sec);
g_printf(">>>nowtime:%s",info);
strcpy(user_msg[MUSIC_NOW_TIME].info,info);
lvgl_user_send_msg(MUSIC_NOW_TIME);
}
void show_music_music_time(u8 min ,u8 sec)
{
u8 info[10];
sprintf(info,"%02d:%02d",min,sec);
g_printf(">>>musictime:%s",info);
strcpy(user_msg[MUSIC_TIME].info,info);
lvgl_user_send_msg(MUSIC_TIME);
}
void lvgl_user_send_msg(u8 msg_event){
int msg[8];
msg[0] = UI_MSG_USER_MSG;
msg[1] = msg_event;
post_ui_msg(msg, 2);
}
void ui_user_msg_dispose(u8 id)
{
switch (id)
{
case MUSIC_SRC:
y_printf(">>%s,[%d]0x%x",__func__,id, user_msg[MUSIC_SRC].info);
lv_label_set_text(guider_ui.screen_MUSIC_SRC, user_msg[MUSIC_SRC].info);
break;
case MUSIC_TIME:
lv_label_set_text(guider_ui.screen_MUSIC_TIME, user_msg[MUSIC_TIME].info);
break;
case MUSIC_NOW_TIME:
lv_label_set_text(guider_ui.screen_NOW_TIME, user_msg[MUSIC_NOW_TIME].info);
break;
default:
break;
}
}
如果跨线程调用的情况会出现以下打印:
LVGL修改文本控件颜色:
参照杰理LVGL指南和LVGL官方手册配置就可以,其中lv_example_label_4()是有幻彩色字体输出,但是使用的是画布储存,占用了(长宽颜色数据量)RAM和CPU,非常占用资源,推荐使用以下函数在驱动层面上换颜色输出渐变数据,修改宏定义即可实现原色彩和渐变设输出。
void led_display_one_frame(COLOUR_RGB rgb[SINGLE_HEIGHT][SINGLE_WIDTH]){
if(!drive_info.drive || !rgb || drive_info.drive->to_flag ||drive_info.drive->frame_next!=drive_info.drive->frame)return;
#if 1//变色
for(int i=0;i<SINGLE_WIDTH;i++){
hsv_tale[i].h= (hsv_tale[i].h+10)%MAX_H;
hsv2rgb(hsv_tale+i,rgb_tale+i);
}
for(int h=0;h<SINGLE_HEIGHT;h++){
for(int w=0;w<SINGLE_WIDTH;w++){
if(rgb[h][w].r ||rgb[h][w].g||rgb[h][w].b){
rgb[h][w]=rgb_tale[w];
}
}
}
#endif
// r_printf("A");
memcpy(drive_info.drive->rgb,rgb,sizeof(drive_info.drive->rgb));
#if 0//直接转换数据
u8 frame_next;
frame_next=(drive_info.drive->frame_next+1)%FRAME_BUFF_NUMBER;
for (int i = 0; i < DEPTH_LEVEL; i++){
led_rgb2spi_data(drive_info.drive->rgb,SINGLE_WIDTH*SINGLE_HEIGHT,drive_info.drive->send_buff[frame_next][i],i);
}
drive_info.drive->frame_next=frame_next;
#else
os_sem_post(&drive_info.sem);
#endif
}
LVGL修改字库字模大小:
生成字库工具:lv_charging_case\res-pack-tools\字库工具\LvglFontTool_V0.4\LvglFontTool\LvglFontTool.exe
以修改为12*12规格字库并显示为例:
- 修改字库:生成之后,替换myFont.c和myFont.bin(),注意__user_font_getdata函数中的内容不要改变

- 修改LVGL相关大小初始化
LVGL DEMO
备注:如果有更新程序,我们会后台更新,请保持关注,谢谢!
代码仓库:
module / 拼接屏 / demo · GitLab
701
lvgl:ac701n_soundbox_sdk-lvgl-led-20240106.7z
内部UI框架:jl701n_soundbox_release_v1.4.2_内部UI框架_io拓展屏驱动歌词滚动显示demo.rar
695
内部UI框架:ac695_310SDK_LEDBOARD_demo.7z
字库工具:unicode字库工具.7z
显示效果
使用内部UI框架进行UI调试的系列步骤
使用内部UI框架进行UI调试的系列步骤.otl
3. 单MCU IO互推LED点阵屏
- AD101C硬件资料 ( 主推) 【金山文档 | WPS云文档】 AD101C 原理图及真值表
AD101C 原理图及真值表.zip - AD101C程序编译加key说明 AD101C程序编译加key说明.otl
- AD101C强制升级工具烧录下载

- 串口升级工具 ad100_uart_update_tools.zip
规范串口升级使用办法:
所有的空片都要先用烧写器烧录一遍程序,然后再使用串口升级,尽可能不使用spi升级,详情请参考下面文档中的第二大点。 AD101C强制升级工具烧录下载(ad100_uart_update_tools)使用说明补充.otl
spi烧录报错问题尝试修改办法(目前测试版本,后续会更新):
AD101C使用强制升级工具spi 烧录不了问题处理(测试版本).otlLCD断码屏
寄存器使用说明
在“AC695N用户手册V1.2.pdf”中第13章:
注意点:LCD断码屏的COM 口只能顺序使用,不能打乱顺序使用。
DEMO程序:
链接:https://pan.baidu.com/s/19OQKNMsSTVAr76FPqfXXAw
提取码:8888
AC460X\AC690X\AC692X LCD屏调式参考资料资料
备注:AC460X、AC690X、AC692X LCD点阵屏这块用的UI工具和程序流程都是一样的。
【金山文档】 17-UI工具
https://kdocs.cn/l/ctouHDb9uOA5
【金山文档】 AC46 UI使用说明
https://kdocs.cn/l/cdJ5QFhxwuPf
【金山文档】 AC692X_lcd点阵屏只显示英文字符说明文档
https://kdocs.cn/l/cbPjE1M70nyo
【金山文档】 12864点阵屏菜单_2018年11月7日170226
https://kdocs.cn/l/cnMCUamOrI2R
【金山文档】 692x频谱-20181220-V1
https://kdocs.cn/l/cgR0UOBhIOQo
DEMO:
【金山文档】 AC692x_SDK_release_V2.6.3(带LCD屏和频谱显示)
https://kdocs.cn/l/chHrN0XdpqCa
- 单线串行控制幻彩灯珠
思路
- 颜色数据(R G B)->SPI数据->do(数据)引脚模拟灯珠通信协议
要点
- 确保spi的数据发送的精确度,系统时钟跑最高、spi时钟跑最高
- 系统时钟:AC695N最高240MHz、AC696N最高192MHz
- spi时钟:如果库里面没有做限制可以设置为 80MHz
- 发送数据时,用最后一个字节的第7位来控制发送完数据之后do引脚的高低电平
- 最后一个字节的bit7为1,发送完数据之后do引脚为高电平,反之亦然。
灯珠资料
- 芯片级联方法

- 数据传输
注:其中 D1 为 MCU 端发送的数据,D2、D3、D4 为级联电路自动整形转发的数据
- 24bit 数据结构
注:高位先发,按照 GRB 的顺序发送数据
- 时序波形

- 通信信号传输定义
| 参数名称 | 参数符号 | 最小值 | 典型值 | 最大值 | 单位 |
|---|---|---|---|---|---|
| 输入 0 码高电平时间 | Tin0h | 0.20 | 0.28 | 0.35 | us |
| 输入 1 码高电平时间 | Tin1h | 0.65 | 0.9 | 1.0 | us |
| 输入 0 码低电平时间 | T0L | 1.55 | 1.72 | 30 | us |
| 输入 1 码低电平时间 | T1L | 1.10 | 1.10 | 30 | us |
| 0 码/1 码周期 | T0/T1 | 1.75 | - | 35 | us |
| RESET 码低电平时间 | reset | 100 | 150 | - | us |
注: a:5050RGB 主要根据高电平时间判断“0”码和“1”码。高电平时间介于 200ns~410ns,IC 判断为“0”码,高电平时间介于 640ns~1000ns,判断为“1”码。 “0”码和“1”码的低电平代表此码结束,准备接收下一数据码。
b:低电平复位时间最小为 100us,为了留有裕度,一帧数据传输过程中(包括 24bit 和 24bit 之间、bit 和 bit 之间)不要中断超过 35us,否则可能会被 IC 认为是 RESET。中断时间在 35us 之内, 控制器可以进行正常数据传输等其他操作。
步骤
- spi波特率
- spi数据发送0x55使用逻辑分析仪看数据高低电平翻转时间T
- 需要同时满足
- 码元周期(T0H+T0L或者T1H+T1L)=T*8
- spi发送数据时高低电平翻转的时间T,必须满足:T0H=Tn1,T0L=T(8-n1);T1H=Tn2,T1L=T(8-n2)
- n1、n2取值1-7
- 转换码
- 使用一个字符spi的发送时间来模拟0码/1码的时序波形
- 字符bit中1/0控制0码/1码时序波形的高和低
- 字符bit中连续的1/0控制0码/1码时序波形的高和低持续时间
eg:
- 如5. 通信信号传输定义T0H 取值范围是0.20us-0.35us T0L 取值范围是1.55us-30us 满足以上两点 - T=0.3us - n1=7 T0H:T0L=1:7 - n2=5 T1H:T1L=5:3 0码:0X80
1码:0XF8
也就是说spi发送0X80就是发送了0码,发送0XF8就是发送1码
- 优化转换码
- spi硬件上发送数据时每两个字节中间会有一个时间间隔
- 发送每个字符第一bit的时间不是很精确
以上两个因素可以使用码元的低电平对时间敏感度低(码元的低电平时间容错时间长)这个特性改善对模拟的波形进行优化。
实际操作就是发送字符的7bit和0bit为0,可以把字符数据整体右移一个bit。
原来的0码0X80变为0X40
原来的1码0XF8变为0X7C
验证spi发送数据是否符合灯的规格
https://kdocs.cn/l/ceRX3DmLZQAq
代码注意点
1. 695 310SDK 、696 170SDK、706 SDK 本身有led spi驱动在led_spi.c文件中
- 706sdk一定要注意程序中的接口是否与下面的接口一样不然会有些问题
- 706音箱sdk初始化接口
/***
#############################音箱 SDK######################################
#706 在使用led_spi.c中的接口去发送数据会遇到映射引脚、与硬件引脚同时有波形
#原因没有断开硬件引脚信号
#设置顺序是要先映射引脚 再断开硬件引脚信号
***/
void led_spi_init(void)
{
if ((u32)LED_SPI == (u32)JL_SPI0) {
spi_do = LED_SPI_PORT;
gpio_set_function(IO_PORT_SPILT(spi_do), PORT_FUNC_SPI0_DA0);//设置引脚映射
SFR(JL_IOMC->IOMC0, 16, 1, 1);//断开硬件引脚信号
request_irq(IRQ_SPI0_IDX, LED_SPI_IRQ_PRIORITY, led_spi_isr, 0);
} else if ((u32)LED_SPI == (u32)JL_SPI1) {
spi_do = LED_SPI_PORT;
gpio_set_function(IO_PORT_SPILT(spi_do), PORT_FUNC_SPI1_DA0);//设置引脚映射
SFR(JL_IOMC->IOMC0, 18, 1, 1);//断开硬件引脚信号
request_irq(IRQ_SPI1_IDX, LED_SPI_IRQ_PRIORITY, led_spi_isr, 0);
}
gpio_set_mode(IO_PORT_SPILT(spi_do), PORT_OUTPUT_LOW);
os_sem_create(&led_spi_sem, 1);
LED_SPI->BUF = 0;
LED_SPI->CON = 0x4021;
LED_SPI->CON1 = 0;
}
- 706无线mic初始化接口
/***
#############################无线mic SDK######################################
#706 在使用led_spi.c中的接口去发送数据会遇到第一个灯的颜色异常
#原因发完数据之后引脚为高电平导致
#LED_SPI->BUF的第7位影响发送完数据引脚电平的高低 不赋值为随机
#LED_SPI->CON1为控制数据发送的流控方式:0:【7,6,5,4,3,2,1,0】1:【0,1,2,3,4,5,6,7】2:【3,2,1,0,7,6,5,4】3:【4,5,6,7,0,1,2,3】
***/
void led_spi_init(void)
{
gpio_set_die(LED_SPI_IO, 1);
gpio_set_direction(LED_SPI_IO, 0);
gpio_set_pull_up(LED_SPI_IO, 0);
gpio_set_pull_down(LED_SPI_IO, 0);
gpio_write(LED_SPI_IO, 0);
gpio_och_sel_output_signal(LED_SPI_IO, OUTPUT_CH_SIGNAL_SPI1_DO);//设置引脚映射
SFR(JL_IOMC->IOMC0, 18, 1, 1);//断开硬件引脚信号
request_irq(IRQ_SPI1_IDX, 0, led_spi_isr, 0);
os_sem_create(&led_spi_sem, 1);
LED_SPI->BUF = 0;
LED_SPI->CON = 0x4021;
LED_SPI->CON1 = 0;
}
2. 刷新数据是使用的定时器尽量使用sys_timer_add等非中断中执行接口
3. 使用spi.c中的接口发送数据时需要在发送时重新设置spi、sys时钟和spi波特率
4. 使用SPI组时,不能将该组的CLK引脚拉去做输出功能(只要初始化了SPI组,该组CLK引脚就会工作),SPI引脚可以映射的话可以使用。
/*
* @brief 设置波特率
* @parm spi spi句柄
* @parm baud 波特率
* @return 0 成功,< 0 失败
*/
int spi_set_baud(spi_dev spi, u32 baud)
{
//SPICK = sysclk / (SPIx_BAUD + 1)
//=> SPIx_BAUD = sysclk / SPICK - 1
u8 id = spi_get_info_id(spi);
u32 sysclk;
#define SYS_CLK_MAX (240000000L)
#define SPI_CLK_MAX (60000000L)
if(SYS_CLK_MAX>clk_get("sys")){
clk_set("sys",SYS_CLK_MAX);
}
// r_f_printf("---------------------------%lu %lu",clk_get("spi"),clk_get("sys"));
if(SPI_CLK_MAX>clk_get("spi")){
r_f_printf("---------------------------%lu",clk_get("spi"));
clk_set("spi",SPI_CLK_MAX);
}
sysclk = clk_get("spi");
// log_debug("spi clock source freq %lu", sysclk);
if (sysclk < baud) {
spi_w_reg_baud(spi_regs[id], 0);
return -EINVAL;
}
spi_w_reg_baud(spi_regs[id], sysclk / baud - 1);
return 0;
}
/*
* @brief spi dma发送
* @parm spi spi句柄
* @parm buf 发送缓冲区基地址
* @parm len 期望发送长度
* @return 实际发送长度,< 0表示失败
*/
int spi_dma_send(spi_dev spi, const void *buf, u32 len)
{
u8 id = spi_get_info_id(spi);
u32 clock = spi_get_info_clock(spi);
int err = spi_set_baud(spi, clock);
if (err ) {
log_error("invalid spi baudrate");
/* return 0; */
}
/* ASSERT((u32)buf % 4 == 0, "spi dma addr need 4-aligned"); */
spi_dir_out(spi_regs[id]);
spi_w_reg_dma_addr(spi_regs[id], (u32)buf);
spi_w_reg_dma_cnt(spi_regs[id], len);
asm("csync");
if (__spi_wait_ok(spi, len)) {
return -EFAULT;
}
return len;
}
/*
* @brief spi 配置dma,不等待pnd,用于中断
* @parm spi spi句柄
* @parm buf 缓冲区基地址
* @parm len 期望长度
* @parm rw 1 接收 / 0 发送
* @return null
*/
void spi_dma_set_addr_for_isr(spi_dev spi, void *buf, u32 len, u8 rw)
{
u8 id = spi_get_info_id(spi);
u32 clock = spi_get_info_clock(spi);
int err = spi_set_baud(spi, clock);
if (err ) {
log_error("invalid spi baudrate");
/* return 0; */
}
/* ASSERT((u32)buf % 4 == 0, "spi dma addr need 4-aligned"); */
rw ? spi_dir_in(spi_regs[id]) : spi_dir_out(spi_regs[id]);
spi_w_reg_dma_addr(spi_regs[id], (u32)buf);
spi_w_reg_dma_cnt(spi_regs[id], len);
}
Demo
1. 697N
- wireless_mic_sdk-v1.3.1_1t1_rx_spi移植成功程序.rar 2. AC692
- 【金山文档】 AC692x_SDK_release_V2.6.3_hsv_rgb
- https://kdocs.cn/l/cc1eZlrIJstW
- 【金山文档】 AC692x_SDK_release_V2.6.3_rgb
- https://kdocs.cn/l/coPpqzea4vlO 3. 695(3.1.0SDK)、696(1.7.0SDK)
4. 701N 1. 141 SDK jl701n_soundbox_release_v1.4.1-spi-rgb.7z
模块有3个buff分别为HSV、RGB、SPI,数据流向是HSV->RGB->SPI
u_config.c配置文件
u_rgb.c模块总入口
u_rgb_drive.c SPI的数据转换与发送
u_rgb_middleware.c中间层设置设置HSV/RGBbuff
u_rgb_hsv.c HSV/RGB数据互转
u_rgb_mode.c 模式扫描与切换的逻辑处理
u_rgb_mode_fun.c 模式的实现



2. 120SDK

3. 可视化soundbox 100P02 DEMO
5. 700N 1. demo 700N自带独立模块推灯,不需要用SPI,demo在sdk里面的cpu\br36\ledc.c
#define RGB_LED_NUM 2//灯的数量
static u8 ledc_test_buf[RGB_LED_NUM * 3] __attribute__((aligned(4)));
void ledc_test(void)
{
printf("************* ledc test **************\n");
ledc_init(&ledc0_data);
//第一个灯
ledc_test_buf[0] = 0;//R
ledc_test_buf[1] = 85;//G
ledc_test_buf[2] = 170;//B
//第二个灯
ledc_test_buf[3] = 170;//R
ledc_test_buf[4] = 85;//G
ledc_test_buf[5] = 0;//B
//2个灯的数据,重发5次,则亮灯数=(5+1)*2=12个
u16 again = 5;
while (1) {
clr_wdt();
ledc_send_rgbbuf(ledc0_data.index, ledc_test_buf, sizeof(ledc_test_buf), again);
delay(150000);
//第一个灯
ledc_test_buf[0] ++;//R
ledc_test_buf[1] ++;//G
ledc_test_buf[2] ++;//B
//第二个灯
ledc_test_buf[3] ++;//R
ledc_test_buf[4] ++;//G
ledc_test_buf[5] ++;//B
}
}
led_spi_700N.c
https://kdocs.cn/l/cczidSVkTGJC
#include "system/includes.h"
static const u8 SPI1_DO[2] = {
IO_PORTC_05,//'A' IO随便选,用的是映射
IO_PORTC_05 //'B'
};
static const u8 SPI2_DO[2] = {
IO_PORTB_07,//'A'
IO_PORT_DM //'B'
};
#define LED_SPI JL_SPI1
#define LED_SPI_PORT 'A'
#define LED_SPI_DAT_BAUD 2
#define LED_SPI_REST_BAUD 15
#define LED_NUM_MAX 2
#define LED_SPI_CLOCK_BASE (clk_get("lsb") / 24000000)
static OS_SEM led_spi_sem;
static u32 spi_do = (u32)-1;
static u8 led_spi_busy = 0;
static u8 led_spi_sus = 0;
___interrupt
void led_spi_isr()
{
LED_SPI->CON &= ~BIT(13); //关闭中断
LED_SPI->CON |= BIT(14); //清pnding
os_sem_post(&led_spi_sem);
led_spi_busy = 0;
}
void led_spi_init(void)
{
if ((u32)LED_SPI == (u32)JL_SPI1) {
spi_do = SPI1_DO[LED_SPI_PORT - 'A'];
SFR(JL_IOMAP->CON1, 4, 1, LED_SPI_PORT - 'A');
request_irq(IRQ_SPI1_IDX, 0, led_spi_isr, 0);
} else {
spi_do = SPI2_DO[LED_SPI_PORT - 'A'];
SFR(JL_IOMAP->CON1, 16, 1, LED_SPI_PORT - 'A');
request_irq(IRQ_SPI2_IDX, 0, led_spi_isr, 0);
}
gpio_set_fun_output_port(spi_do, FO_SPI1_DA0, 1, 1, LOW_POWER_FREE);//7000系列用的是Crossbar
os_sem_create(&led_spi_sem, 1);
LED_SPI->CON = 0x4021;
}
void led_rgb_to_24byte(u8 r, u8 g, u8 b, u8 *buf)
{
u32 dat = ((g << 16) | (r << 8) | b);
for (u8 i = 0; i < 24; i ++) {
if (dat & BIT(23 - i)) {
*(buf + i) = 0x7c;
} else {
*(buf + i) = 0x60;
}
}
}
void led_rest()
{
u8 tmp_buf[16] = {0};
LED_SPI->BAUD = (LED_SPI_REST_BAUD + 1) * LED_SPI_CLOCK_BASE - 1;
LED_SPI->CON |= BIT(14);
LED_SPI->ADR = (u32)tmp_buf;
LED_SPI->CNT = 16;
while (!(LED_SPI->CON & BIT(15)));
LED_SPI->CON |= BIT(14);
}
void led_spi_send_rgbbuf(u8 *rgb_buf, u16 led_num) //rgb_buf的大小 至少要等于 led_num * 24
{
if (!led_num) {
return;
}
if (led_num > LED_NUM_MAX) {
led_num = LED_NUM_MAX;
}
while (led_spi_sus) {
os_time_dly(1);
}
led_spi_busy = 1;
led_rest();
LED_SPI->BAUD = (LED_SPI_DAT_BAUD + 1) * LED_SPI_CLOCK_BASE - 1;
LED_SPI->CON |= BIT(14);
LED_SPI->ADR = (u32)rgb_buf;
LED_SPI->CNT = led_num * 24;
while (!(LED_SPI->CON & BIT(15)));
LED_SPI->CON |= BIT(14);
led_spi_busy = 0;
}
void led_spi_send_rgbbuf_isr(u8 *rgb_buf, u16 led_num) //rgb_buf的大小 至少要等于 led_num * 24
{
if (!led_num) {
return;
}
if (led_num > LED_NUM_MAX) {
led_num = LED_NUM_MAX;
}
while (led_spi_sus) {
os_time_dly(1);
}
led_spi_busy = 1;
os_sem_pend(&led_spi_sem, 0);
led_rest();
LED_SPI->BAUD = (LED_SPI_DAT_BAUD + 1) * LED_SPI_CLOCK_BASE - 1;
LED_SPI->CON |= BIT(14);
LED_SPI->ADR = (u32)rgb_buf;
LED_SPI->CNT = led_num * 24;
LED_SPI->CON |= BIT(13);//打开中断
}
u8 led_spi_suspend(void)
{
if (led_spi_sus) {
return 1;
}
if (led_spi_busy) {
return 1;
}
LED_SPI->CON |= BIT(14);
LED_SPI->CON &= ~BIT(0);
led_spi_sus = 1;
return 0;
}
u8 led_spi_resume(void)
{
if (!led_spi_sus) {
return 0;
}
gpio_set_fun_output_port(spi_do, FO_SPI1_DA0, 1, 1, LOW_POWER_FREE);//7000系列用的是Crossbar
LED_SPI->CON = 0x4021;
led_spi_sus = 0;
return 0;
}
static u8 spi_dat_buf[24 * LED_NUM_MAX] __attribute__((aligned(4)));
extern void wdt_clear();
//测试程序
void led_spi_test(void)
{
printf("****************** led spi test *******************\n");
led_spi_init();
u8 cnt = 0;
u8 pulse = 0;
while (1) {
cnt ++;
led_rgb_to_24byte(cnt, 255 - cnt, cnt, (u8 *)(&spi_dat_buf[0]));
led_rgb_to_24byte(255 - cnt, cnt, 255 - cnt, (u8 *)(&spi_dat_buf[24]));
#if 1
led_spi_send_rgbbuf(spi_dat_buf, 2); //等待的方式,建议用在发的数据量小的场合
#else
led_spi_send_rgbbuf_isr(spi_dat_buf, 2); //中断的方式,建议用在发的数据量大的场合
#endif
os_time_dly(2);
wdt_clear();
}
}
2. 138SDK
led-spi-hsv-JL700N_earphone_release_V1.3.8.7z
6. 703N 1. 2.0.0-P01.04 703-suoundbox-2.0.0-P01.04-spi-rgb.7z
- LEDC 模块控制单线灯珠
- 模块代码:ledc_rgb_hsv.7z
- 适用范围 适用于所有带LEDC硬件模块的sdk

- 适用范围 适用于所有带LEDC硬件模块的sdk
- 模块代码:ledc_rgb_hsv.7z
- 硬件上支持2~3路(需要看用户手册)ledc
- 多个时间单位可选,兼容更多规格灯珠
typedef enum {
ut_21ns=1,
ut_42ns=2,
ut_63ns=3,
ut_125ns=6,
ut_250ns=12,
ut_500ns=24,
ut_1us=48,
ut_2us=96,
ut_4us=192,
}t_unit_en;
- 通过配置0/1码值更方便适配不同规格灯珠
typedef struct reg_platform_data {
u32 index; //控制器号
u32 port; //输出引脚
u32 idle_level; //当前帧的空闲电平,0:低电平, 1:高电平
u32 out_inv; //起始电平,0:高电平开始, 1:低电平开始
u32 bit_inv; //取数据时高低位镜像,0:不镜像,1:8位镜像,2:16位镜像,3:32位镜像
t_unit_en t_unit; //时间单位
u32 t1h_cnt; //1码的高电平时间 = t1h_cnt * t_unit;
u32 t1l_cnt; //1码的低电平时间 = t1l_cnt * t_unit;
u32 t0h_cnt; //0码的高电平时间 = t0h_cnt * t_unit;
u32 t0l_cnt; //0码的低电平时间 = t0l_cnt * t_unit;
u32 t_rest_cnt; //复位信号时间 = t_rest_cnt * t_unit;
void (*cbfun)(void);//中断回调函数
}reg_data;
2. 模块基础配置
LEDC_RGB_INFO info={
.drive={
#ifdef LEDC_0
[LEDC_0]{.num/*灯的个数*/=1,.io={IO_PORTC_03/*io口*/,NO_CONFIG_PORT/*绑定io口*/},.cbfun=send_isr_0/*发完数据之后中断回调接口*/,.cnt=0/*重复发送数据次数 亮灯的个数=numb*(cnt+1)*/},
#endif
#ifdef LEDC_1
[LEDC_1]{.num/*灯的个数*/=1,.io={IO_PORTA_02/*io口*/,NO_CONFIG_PORT/*绑定io口*/},.cbfun=send_isr_1/*发完数据之后中断回调接口*/,.cnt=1/*重复发送数据次数 亮灯的个数=numb*(cnt+1)*/},
#endif
#ifdef LEDC_2
[LEDC_2]{.num/*灯的个数*/=1,.io={IO_PORTA_04/*io口*/,NO_CONFIG_PORT/*绑定io口*/},.cbfun=send_isr_2/*发完数据之后中断回调接口*/,.cnt=2/*重复发送数据次数 亮灯的个数=numb*(cnt+1)*/},
#endif
},
};
1. 初始化
/*
背景: 发送数据的时间远小于run color的时间间隔
线程1
1. 判断线程2是否完成发送数据
2. 没有在发送数据
3. 颜色变化
4. 发送信号量同步状态
5. 循环步骤1-4
线程2
1. 等待颜色变化处理完成
2. 发送数据
3. 循环步骤1-2
*/
#ifdef LEDC_0
create_rgb_task(&info.drive[LEDC_0],run_color_0/*改变颜色数据定时器回调接口*/,U_RGB_TASK_NAME_0);
#endif
#ifdef LEDC_1
create_rgb_task(&info.drive[LEDC_1],run_color_1/*改变颜色数据定时器回调接口*/,U_RGB_TASK_NAME_1);
#endif
#ifdef LEDC_2
create_rgb_task(&info.drive[LEDC_2],run_color_2/*改变颜色数据定时器回调接口*/,U_RGB_TASK_NAME_2);
#endif
2. 数据的修改
static void run_color_2(const LEDC_DRIVE_INFO *drive){
//避免在转换数据的时候修改源数据
if(drive->send){
return;
}
// r_printf("change color");
for(int i=0;i<drive->num;i++){
drive->hsv[i].h=(drive->hsv[i].h+1)%MAX_H;
hsv2rgb(drive->hsv+i,drive->rgb+i);
}
os_sem_post(&drive->sem);
}
2. DEMO
1. 703:
SKD1.0.0:703soundbox1.0.0SDK-LEDC-HSV-RGB.7z
2. 700: SDK1.3.8:ledc-rgb-hsv-JL700N_earphone_release_V1.3.8.7z
7. 692V263-SDK-繁体字库显示 需要用到ASCII.exe转码工具
在上面获取码表后,填入需要显示的数组中:
download.bat需要添加 BIG5的编码
公版PWM_LED TWS呼吸灯同步呼吸功能,支持单IO和双IO推灯,支持单灯呼吸同步、双灯交替呼吸同步
【金山文档】 AC897N_AD697N_earphone_release_V2.3.5_tws呼吸灯同步
https://kdocs.cn/l/clgVi7uS3QvALVGL字库 字库工具:LvglFontTool_V0.4.rar
资料1:https://www.kdocs.cn/l/cp7abZRrK2u7 资料2:LVGL修改字库字模大小
字库文字的添加:视频文件
歌词显示器开发注意项 歌词显示器开发注意项.otl
FAQ
- 数码管显示会抖/闪屏问题
- 提高扫屏中断的优先级(提到6),把扫屏代码放在ram中扫屏的代码必须在RAM,不然会出现死机,不屏蔽中断
#define TCFG_LED7_RUN_RAM 1 //led7跑ram 不屏蔽中断(需要占据2k附近ram)
- 【重点留意】:AC695 SDK irq_config.c没有上面宏定义包进去,导致中断优先级没有改为6 修改方法:
SDK\apps\soundbox\board\br23\irq_config.c
- LED7数码管出现有的暗有的亮的情况解决思路分享 首先在确保IO都配置为相同的强驱,配置的强驱电流大小要相同。
造成亮暗不一致的原因:
我们以7次扫描为一个循环状态,假如一循环中2脚只点亮一个管,那么这个时候是最亮的,如果点亮了四个管,这个时候是最暗的。
解决方法:
根据每个IO一个循环需要点亮的灯数,设置不同PWM的占空比,控制亮暗。
参考案例,以692为例:
【金山文档】 AC692x_SDK_release_V2.6.3_亮暗不一致
https://kdocs.cn/l/cfhjUZnCKdkh
思路二: 确保每个数码管段的电流基本一致,出现亮暗不一致原因,排除硬件问题后,基本上与每次点亮的数码管段个数有关。
以AC6921A8为例,公版推数码管使用的是PA组和PC组口,普通输出能力是8mA,开强驱输出能力是24mA,公版默认会全部开强驱,一下情况下电流情况如下:(芯片输入电流能力会略大于输出电流能力)
| 每次推LED数 | 共阳 | 共阴 |
|---|---|---|
| 1 | 24mA | 24mA |
| 2 | 12mA | >12mA |
| 3 | 8mA | >8mA |
| 4 | 6mA | >6mA |
由上表可以看出,公版配置可能会出现电流不一样情况,导致固定有的段会亮,有的段会灭。因此可以配置为共阴接法,默认全部关强驱,当IO为共阴极的情况下,打开强驱,增强IO输入电流能力(24mA),输出高的情况下,关闭强驱(8mA),这样的情况下每个段的电流都近似于8mA,能够有效解决亮暗不一致的问题。
修改方法:
/*----------------------------------------------------------------------------*/
/**@brief LED清屏函数
@param x:显示横坐标
@return void
@author Change.tsai
@note void led7_clear(void)
*/
/*----------------------------------------------------------------------------*/
void led7_clear(void)
{
//======C======
LEDN_C_PORT_OUT &= ~(BIT(LEDN_S0_BIT) | BIT(LEDN_S1_BIT) | BIT(LEDN_S3_BIT) | BIT(LEDN_S5_BIT) | BIT(LEDN_S6_BIT));
LEDN_C_PORT_DIR |= (BIT(LEDN_S0_BIT) | BIT(LEDN_S1_BIT) | BIT(LEDN_S3_BIT) | BIT(LEDN_S5_BIT) | BIT(LEDN_S6_BIT));
LEDN_C_PORT_PU &= ~(BIT(LEDN_S0_BIT) | BIT(LEDN_S1_BIT) | BIT(LEDN_S3_BIT) | BIT(LEDN_S5_BIT) | BIT(LEDN_S6_BIT));
LEDN_C_PORT_PD &= ~(BIT(LEDN_S0_BIT) | BIT(LEDN_S1_BIT) | BIT(LEDN_S3_BIT) | BIT(LEDN_S5_BIT) | BIT(LEDN_S6_BIT));
LEDN_C_PORT_HD &= ~(BIT(LEDN_S0_BIT) | BIT(LEDN_S1_BIT) | BIT(LEDN_S3_BIT) | BIT(LEDN_S5_BIT) | BIT(LEDN_S6_BIT) );
//======A=====
LEDN_A_PORT_OUT &= ~( BIT(LEDN_S2_BIT) | BIT(LEDN_S4_BIT) );
LEDN_A_PORT_DIR |= ( BIT(LEDN_S2_BIT) | BIT(LEDN_S4_BIT) );
LEDN_A_PORT_PU &= ~( BIT(LEDN_S2_BIT) | BIT(LEDN_S4_BIT) );
LEDN_A_PORT_PD &= ~(BIT(LEDN_S2_BIT) | BIT(LEDN_S4_BIT) );
LEDN_A_PORT_HD &= ~( BIT(LEDN_S2_BIT) | BIT(LEDN_S4_BIT) );
}
/*----------------------------------------------------------------------------*/
/**@brief LED扫描函数
@param void
@return void
@author Change.tsai
@note void led7_scan(void *param)
*/
/*----------------------------------------------------------------------------*/
void led7_scan(void *param)
{
static u8 cnt;
u8 seg;
u8 user_seg;
LED_drive7();
seg = led7_var.bShowBuff1[cnt];
user_seg = seg;
// printf("user_seg[%d]==%d\n",cnt,user_seg);
led7_clear();
switch (cnt) {
case 0:
// LEDN_C_PORT_PU |= BIT(LEDN_S0_BIT);
LEDN_C_PORT_OUT &= ~BIT(LEDN_S0_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S0_BIT);
LEDN_C_PORT_HD |= BIT(LEDN_S0_BIT);
break;
case 1:
// LEDN_C_PORT_PU |= BIT(LEDN_S1_BIT);
LEDN_C_PORT_OUT &= ~BIT(LEDN_S1_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S1_BIT);
LEDN_C_PORT_HD |= BIT(LEDN_S1_BIT);
break;
case 2:
// LEDN_A_PORT_PU |= BIT(LEDN_S2_BIT);
LEDN_A_PORT_OUT &= ~ BIT(LEDN_S2_BIT);
LEDN_A_PORT_DIR &= ~BIT(LEDN_S2_BIT);
LEDN_A_PORT_HD |= BIT(LEDN_S2_BIT);
break;
case 3:
// LEDN_C_PORT_PU |= BIT(LEDN_S3_BIT);
LEDN_C_PORT_OUT &= ~ BIT(LEDN_S3_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S3_BIT);
LEDN_C_PORT_HD |= BIT(LEDN_S3_BIT);
break;
case 4:
// LEDN_A_PORT_PU |= BIT(LEDN_S4_BIT);
LEDN_A_PORT_OUT &= ~ BIT(LEDN_S4_BIT);
LEDN_A_PORT_DIR &= ~BIT(LEDN_S4_BIT);
LEDN_A_PORT_HD |= BIT(LEDN_S4_BIT);
break;
case 5:
// LEDN_C_PORT_PU |= BIT(LEDN_S5_BIT);
LEDN_C_PORT_OUT &= ~ BIT(LEDN_S5_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S5_BIT);
LEDN_C_PORT_HD |= BIT(LEDN_S5_BIT);
break;
case 6:
// LEDN_C_PORT_PU |= BIT(LEDN_S6_BIT);
LEDN_C_PORT_OUT &= ~ BIT(LEDN_S6_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S6_BIT);
LEDN_C_PORT_HD |= BIT(LEDN_S6_BIT);
break;
default :
break;
}
if (seg & BIT(0)) {
// LEDN_C_PORT_PD |= BIT(LEDN_S0_BIT);
LEDN_C_PORT_OUT |= BIT(LEDN_S0_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S0_BIT);
}
if (seg & BIT(1)) {
// LEDN_C_PORT_PD |= BIT(LEDN_S1_BIT);
LEDN_C_PORT_OUT |= BIT(LEDN_S1_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S1_BIT);
}
if (seg & BIT(2)) {
// LEDN_A_PORT_PD |= BIT(LEDN_S2_BIT);
LEDN_A_PORT_OUT |= BIT(LEDN_S2_BIT);
LEDN_A_PORT_DIR &= ~BIT(LEDN_S2_BIT);
}
if (seg & BIT(3)) {
// LEDN_C_PORT_PD |= BIT(LEDN_S3_BIT);
LEDN_C_PORT_OUT|= BIT(LEDN_S3_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S3_BIT);
}
if (seg & BIT(4)) {
// LEDN_A_PORT_PD |= BIT(LEDN_S4_BIT);
LEDN_A_PORT_OUT |= BIT(LEDN_S4_BIT);
LEDN_A_PORT_DIR &= ~BIT(LEDN_S4_BIT);
}
if (seg & BIT(5)) {
// LEDN_C_PORT_PD |= BIT(LEDN_S5_BIT);
LEDN_C_PORT_OUT |= BIT(LEDN_S5_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S5_BIT);
}
if (seg & BIT(6)) {
// LEDN_C_PORT_PD |= BIT(LEDN_S6_BIT);
LEDN_C_PORT_OUT |= BIT(LEDN_S6_BIT);
LEDN_C_PORT_DIR &= ~BIT(LEDN_S6_BIT);
}
cnt = (cnt >= 7) ? 0 : cnt + 1;
}
- AC695N 开启spi推屏 ui_task 会影响到dac L trim数值,导致DAC左声道播放会出现杂音("po声") 按照AC695X软件问题整理文档 第198点修改:
AC695X软件问题整理.doc - AC695N 使用内部框架推点阵屏需要高亮显示操作 控件高亮显示功能 ,点阵屏需要使用 int ui_invert_element_by_id(int id); 但是该接口只改变了显存的内容,并没有更新显存到屏幕
需要新增接口
在设置完高亮后,需要刷一遍屏幕
