当前位置:   article > 正文

嵌入式Linux视频笔记----i.MX6ULL裸机开发_imx6ull视频解码

imx6ull视频解码

第88讲 LCD显示实验_哔哩哔哩_bilibili

ARM芯片本身基本介绍,裸机开发基本知识

第2遍看视频,增加截图、代码

关于ubuntu网络

我的win10主机通过wifi联网,在 嵌入式Linux视频笔记----Linux基础入门  的 P26 第25讲-安装NFS服务器 这一讲中我自己为了实现nfs,使用网线连接,按照其中设置,导致ubuntu无法联网。

现在将ubuntu联网方式记录如下【参考irtualbox+Ubuntu配置网络(桥接网络)】:

1、桥接网卡改为wifi

2、ubuntu与win10的IP设为同一网段,随后可以互相ping通

3、配置ubuntu DNS【缺点:每次都需要重新配置】

sudo vi /etc/resolv.conf

P1 第68讲 I.MX6ULL启动方式

芯片手册【3619页】、开发板原理图获取方式

启动模式设置三大模式--熔丝、外部 USB 串口、内部 SD卡 eMMc NAND;内部介质;
接口编号;介质属性;

芯片手册:具体引脚,启动模式设置中涉及的8个引脚

手册 8.2.1
手册 8.5​​​
手册 5.1
野火开发板

P2 第69讲 I.MX6ULL镜像文件

boot ROM内置程序:选择内部启动方式,启动boot ROM程序【芯片出厂前固化,用户无法变更】;初始化时钟、DDR3【从DCD获取信息】、从外部存储介质加载代码【从Boot data获取加载地址和大小】

镜像5要素:空偏移;image vector table IVT--1个结构体【包含Boot data 和DCD的位置,进而找到Boot data 和DCD】;Boot data--镜像在内存中的加载地址和大小;Device configuration data--DCD、寄存器初始化列表;bin文件--程序文件。

手册 8.7.1
表格位于手册 8.7.1
表格位于手册 8.7.1
“镜像”指包含空偏移

P3 第70讲 SDK方式烧录镜像

自动添加上一节讲的3部分信息:IVT、boot data、DCD

获取NXP官方SDK:官网、Linux平台

NXP SDK linux官网链接【需注册】

Linux中安装【下载,直接执行run文件

查看readme、详细解读脚本文件

查看readme
  1. mkimage.sh
  2. #!/bin/bash
  3. function usage()
  4. {
  5. echo "Usage: $0 target"
  6. echo " target: ram -- the image will be loaded to RAM and run, the application must be built with ram link file"
  7. echo " target: flash -- the image will be run on flash directly, the application must be build with flash link file"
  8. echo " target: sd -- the image will be loaded from SD to RAM and run, the application must be build with ram link file"
  9. echo "Example: $0 ram"
  10. }
  11. if [ "$#" -ne 1 ]; then # 参数个数不是1个,则给出提示信息
  12. usage $0
  13. exit 1
  14. fi
  15. SYSTEM=`uname -s` # 获取主机类型 Linux
  16. if [ $SYSTEM == "Linux" ]; then
  17. DCD_BUILDER=dcdgen.bin # 2个程序赋值
  18. IMG_BUILDER=imgutil.bin
  19. else
  20. DCD_BUILDER=dcdgen.exe
  21. IMG_BUILDER=imgutil.exe
  22. fi
  23. ../bin/$DCD_BUILDER dcd.config dcd.bin # 执行 dcdgen.bin 程序,根据dcd.config生成dcd.bin【dcd.config和本脚本在相同路径,主要是ddr配置信息】
  24. if [ "$1" == "ram" ]; then # 传递给脚本的第1个参数,注意 dcd_file为刚生成的dcd.bin,app_file为用户程序
  25. ../bin/$IMG_BUILDER --combine base_addr=0x80000000 ivt_offset=0x1000 app_offset=0x2000 dcd_file=dcd.bin app_file=sdk20-app.bin ofile=sdk20-app.img image_entry_point=0x80002000
  26. elif [ "$1" == "flash" ]; then
  27. ../bin/$IMG_BUILDER --combine base_addr=0x60000000 ivt_offset=0x1000 app_offset=0x2000 dcd_file=dcd.bin app_file=sdk20-app.bin ofile=sdk20-app.img image_entry_point=0x60002000
  28. elif [ "$1" == "sd" ]; then
  29. ../bin/$IMG_BUILDER --combine base_addr=0x80000000 ivt_offset=0x400 app_offset=0x2000 dcd_file=dcd.bin app_file=sdk20-app.bin ofile=sdk20-app.img image_entry_point=0x80002000
  30. else
  31. echo "Unsupported target $1"
  32. usage $0
  33. fi

野火烧录工具:模仿官方SDK【dcd.config与官方完全一致,DDR与官方相同。重写mkimage.sh】;解压缩 看脚本文件、相比官方增加了烧录功能;演示用法

电脑插入SD卡后ubuntu相应设置
本机实测
视频效果,后来用mkimage.sh时提到sd卡有问题,更换sd卡后与我实测显示一致
  1. mkimage.sh
  2. #!/bin/bash
  3. function usage()
  4. {
  5. echo "Usage: $0 file"
  6. echo " file : the image which you want to burn "
  7. echo "Example: $0 helloworld.bin"
  8. }
  9. cur_user=`env | grep USER | cut -d "=" -f 2` # 从环境变量中提取USER
  10. echo $cur_user
  11. if [ $cur_user == "root" ]; then # 当前是root用户则报错
  12. echo -e "\033[31mThe cur_user is $cur_user. Please run the script with a normal user.\033[0m"
  13. exit 1
  14. fi
  15. if [ "$#" -ne 1 ]; then
  16. usage $0
  17. exit 1
  18. fi
  19. SYSTEM=`uname -s`
  20. if [ $SYSTEM == "Linux" ]; then
  21. DCD_BUILDER=dcdgen.bin
  22. IMG_BUILDER=imgutil.bin
  23. else
  24. exit 1
  25. fi
  26. cat /proc/partitions
  27. while true
  28. do
  29. read -p "Please Input the card ID [a~z]: (Input 'exit' for quit):" dev_index
  30. case $dev_index in
  31. [[:lower:]]) break
  32. ;;
  33. exit) exit 0
  34. ;;
  35. * ) echo -e "\033[31mInvalid parameter!\033[0m"
  36. echo -e "\033[31mThe parameter should be between a~z, enter 'exit' to quit.\033[0m"
  37. echo -e "\033[34mUsage: If the SD card device corresponds to /dev/sdd, enter d\033[0m"
  38. continue
  39. ;;
  40. esac
  41. done
  42. sd_idnex=sd$dev_index # 如果SD卡路径为 /dev/sdb ,$dev_index=b,sd_idnex=sdb
  43. echo $sd_index
  44. if [ ! -e /dev/$sd_idnex ]; then # 文件不存在【-e 选项表示检查文件是否存在】
  45. echo "mkimage : /dev/$sd_idnex : No such file or directory"
  46. exit 1
  47. fi
  48. if [ ! -x $DCD_BUILDER ]; then # 如果没有执行权限则增加执行权限【-x 选项表示检查文件是否可执行】
  49. chmod +x $DCD_BUILDER
  50. fi
  51. if [ ! -x $IMG_BUILDER ]; then
  52. chmod +x $IMG_BUILDER
  53. fi
  54. ./$DCD_BUILDER dcd.config dcd.bin #ivt表基地址0x80000000、bin文件链接地址0x80002000
  55. ./$IMG_BUILDER --combine base_addr=0x80000000 ivt_offset=0x400 app_offset=0x2000 dcd_file=dcd.bin app_file=$1 ofile=sdk20-app.img image_entry_point=0x80002000
  56. sudo dd if=sdk20-app.img of=/dev/$sd_idnex bs=512 conv=fsync # 使用dd命令将sdk20-app.img文件的内容写入SD卡
脚本用法演示,test.bin为空文件,仅仅演示用

P4 第71讲 ARM-V7架构

运行模式9种模式      用户--资源访问受限;系统--无限制;一般中断--硬件中断;快速中断--高速信号;管理--上电默认、初始化、软中断;数据访问终止--非法访问;未定义指令--跑飞了;用户安全扩展、虚拟化扩展

寄存器组通用寄存器组r0~r15【sp、lr、pc】;程序状态寄存器cpsr spsr;系统寄存器 cp15

P5 第72讲 ARM常用汇编指令

汇编格式、常用段名、常见伪操作、寄存器间数据传输【非通用寄存器操作对应专用指令】、内存与寄存器数据传输、压栈 出栈、跳转、算术运算、逻辑运算

P6 第73讲 VSCode编辑器

官网下载安装,终端code打开软件
特点--无需新建项目,直接打开文件夹;不同目录文件夹可保存至工作区;默认预览模式【打开后文件名斜体,再打开新文件,旧文件自动关闭】

关闭预览模式:取消黄色框选中


推荐插件:c/c++【按ctrl后跳转】;Chinese;material theme UI;CodeSpell Checker;Bracket Pair Colorizer;rainbow-highlighter

高效工作:快捷键

VsCode 跳转到函数之后怎么跳转回之前的位置:Ctrl + Alt + '-'【注意不是小键盘的-】

P7 第74讲 GPIO控制原理

数量5组,1组最多32个,总共124个

视频中手册4127页,比我的新

时钟:CCM_CCGR1

引脚复用、引脚属性

 

控制GPIO引脚

小结

P8 第75讲 汇编点亮LED

调整vscode字体 monospace、加入汇编插件ARM

终端字体设置

对比寄存器逐行写代码

  1. .global _start #定义全局标号
  2. _start:
  3. @是能GPIO时钟
  4. ldr r0,=0x20c406c #把立即数【CCM_CCGR1地址】加载到寄存器
  5. ldr r1,=0xffffffff #本应该是0x3<<26位,对应GPIO1 CLOCK配置【除停止模式外,该外设时钟全程使能】
  6. str r1,[r0] #寄存器数据写入到内存,[]可以理解为指针
  7. @设置引脚复用为GPIO
  8. ldr r0,=0x20e006c #把立即数【SW_MUX_CTL Register 地址】加载到寄存器
  9. ldr r1,=5 #0101配置为GPIO1_IO04
  10. str r1,[r0]
  11. @设置引脚属性【上下拉/速率/驱动能力,具体配置参考硬件工程师建议或SDK包的配置】
  12. ldr r0,=0x20e02f8 #把立即数【SW_PAD_CTL Register 地址】加载到寄存器
  13. ldr r1,=0x10b0 #具体配置参考SDK包的配置
  14. str r1,[r0]
  15. @控制GPIO引脚输出高低电平
  16. ldr r0,=0x209c004 #把立即数【GPIOx_GDIR Register 地址】加载到寄存器
  17. ldr r1,=16 #GPIO的第4位配置为输出
  18. str r1,[r0]
  19. ldr r0,=0x209c000 #把立即数【GPIOx_DR Register 地址】加载到寄存器
  20. ldr r1,=0 #GPIO的第4位配置为低电平【简单起见,全为0
  21. str r1,[r0]

程序编译:下载裸机gcc编译器 gcc-arm-none-eabi【none指裸机,对应linux】、编译、链接、得到bin文件、添加头信息并烧录、开发板上电验证

第3条目的是为了指定链接地址

sudo apt-get install gcc-arm-none-eabi

arm-none-eabi-gcc -c led.s -o led.o

arm-none-eabi-ld -Ttext 0x80000000 led.o -o led.elf

arm-none-eabi-objcopy -O binary led.elf led.bin

cd ~/workdir/LinuxCode/bare_mental/part_1/download_tool/

./mkimage.sh ~/workdir/embed_linux_tutorial/base_code/bare_metal/part_2_gzc/led.bin

注意wifi的跳线帽要换到远离wifi一侧

P9 第76讲 使用c语言和sdk

vscode工作区用法:先打开文件夹A,“文件”-->“将工作区另存为”,命名保存,“文件”-->“将文件夹添加到工作区

使用官方sdk:包含寄存器宏定义,避免反复查datasheet;

使用C:bin文件段;c环境--bss段清0、栈指针设置;裸机控制外设--外设对应寄存器;
链接脚本lds文件;Makefile修改

P10 第77讲 按键检测输入

按下一次灯状态翻转

按键key硬件原理图

程序实现

P11 第78讲 工程文件整理和中断头文件移植

文件整理:source文件夹按模块文件夹存放文件;source/common存放共用函数;source/project存放main、启动文件;include文件夹存放sdk移植头文件;Makefile修改路径
中断头文件移

工程文件及分类​​​​​

P12 第79讲 通用中断控制器(GIC)

ARM有4个版本规范,A7使用V2 GIC-400

GIC-400是根据GIC规范设计的具体硬件产品


GIC结构:信号源--软件中断、私有中断、共享中断 使用最多 多核共享;分发器--中断信号到cpu接口单元;cpu接口单元--分发器到cpu、保存中断ID

竟然有上千个中断!!!

 


获取GIC基地址:芯片手册;cp15协处理器--16个协处理器【1个协处理器=一大类寄存器】、功能需要配置、配置为CBAR SCTLR VBAR

P13 第80讲 中断向量表

针对ARMv7-A

一级查表:自动跳转指定位置运行;写死在start.s文件中;

start.s文件中的一级查表


二级查表:在sdk的头文件中;

MCIMX6Y2.h文件中的二级查表

P14 第81讲 中断处理流程

汇编+C语言

中断上下文:内核寄存器进入中断前的值

具体流程:cps设置cpsr进入IRQ模式、初始化栈指针【不同模式栈不同】、push、获取中断编号、执行中断代码、还原现场、返回原程序

三级流水线:取指令、译指令、执行指令

P15 第82讲 按键中断实验

上电先进汇编代码复位中断,随后跳转到C代码main

C语言内嵌汇编:c语言读cp15协处理器,详细解释几行代码

IO中断相关

P16 第83讲 位置无关码和重定位

程序执行和变量访问方式:pc指针+偏移地址;绝对地址

位置无关码--pc指针+偏移地址、普通代码段、局部变量、可在任意内存运行;

位置相关码--绝对地址、必须在指定运行地址运行。

重定位:利用位置无关码将位置相关码加载到指定位置

data_start=0x85000000
data_end =0x85000000+*(.data)长度
上电复位时执行这2段汇编代码
加载data段  清零bss段

bin加载地址

这条命令使用hexdump工具来查看sdk20-app.img文件的十六进制和ASCII码。-n 50表示只显示文件的前50个字节,-C表示以规范的十六进制+ASCII码格式输出,-s 1024表示从文件的第1024个字节【SD卡镜像有1K的空偏移】开始显示。 

输出的前4个字节为IVT header,随后4个字节为bin文件链接地址0x8000 2000

P17 第84讲 时钟控制模块

时钟的4个层次:晶振、PL PFD、PLL选择、根时钟/外设时钟

系统时钟:24MHz、RTC时钟

PLL PFD倍频:7路PLL

手册10.3.1

PLL选择时钟:分频、选择

手册 ​​​​​18.5.1.5

根时钟/外设时钟:时钟树

手册 18.3

P18 第85讲 主频修改实验

对照上一讲介绍代码【学习阶段不要一个一个查寄存器,把握总体框架即可。除非做项目有需求】

  1. //4层时钟设置
  2. #include "clock.h"
  3. void system_clock_init(void)
  4. {
  5. /******************* 第一层时钟设置--晶振时钟***********************/
  6. if ((CCM->CCSR & (0x01 << 2)) == 0) //CPU 使用的是 ARM PLL
  7. {
  8. /*将CPU时钟切换到XTAL (OSC) 时钟*/
  9. CCM->CCSR &= ~(0x01 << 8); //控制CCSR: step_sel ,选择 osc_clk 作为时钟源
  10. CCM->CCSR |= (0x01 << 2); //设置GLITCHLESS MUX 选择 step_clk 作为时钟源
  11. }
  12. /******************* 第二层时钟设置--PLL时钟***********************/
  13. /*设置PLL1输出时钟为792MHz,它将作为CPU时钟*/
  14. CCM_ANALOG->PLL_ARM |= (0x42 << 0);
  15. /*将CPU 时钟重新切换到 ARM PLL【初始化好PLL1就不直接用晶振了】*/
  16. CCM->CCSR &= ~(0x01 << 2);
  17. /*设置时钟分频系数为0,即不分频*/
  18. CCM->CACRR &= ~(0x07 << 0); //清零分频寄存器 不分频
  19. //CCM->CACRR |= (0x07 << 0); // 8分频
  20. /*设置PLL2(System PLL) 输出时钟*/
  21. /* Configure SYS PLL to 528M */
  22. CCM_ANALOG->PLL_SYS_SS &= ~(0x8000); //使能PLL2 PFD输出
  23. CCM_ANALOG->PLL_SYS_NUM &= ~(0x3FFFFFFF);//设置分频系数为0,即不分频。
  24. CCM_ANALOG->PLL_SYS |= (0x2000); //使能PLL2 输出
  25. CCM_ANALOG->PLL_SYS |= (1 << 0); //设置输出频率为528M
  26. while ((CCM_ANALOG->PLL_SYS & (0x80000000)) == 0) //等待设置生效
  27. {
  28. }
  29. /*设置PLL3(System PLL) 输出时钟*/
  30. /* Configure USB PLL to 480M */
  31. CCM_ANALOG->PLL_USB1 |= (0x2000); //使能 PLL3时钟输出
  32. CCM_ANALOG->PLL_USB1 |= (0x1000); //PLL3上电使能
  33. CCM_ANALOG->PLL_USB1 |= (0x40); // 使能USBPHYn
  34. CCM_ANALOG->PLL_USB1 &= ~(0x01 << 0);//设置输出频率为480MHz
  35. while ((CCM_ANALOG->PLL_SYS & (0x80000000)) == 0)//等待设置生效
  36. {
  37. }
  38. /*关闭暂时不使用的 PLL4 、PLL5 、PLL6 、PLL7*/
  39. CCM_ANALOG->PLL_AUDIO = (0x1000); //关闭PLL4
  40. CCM_ANALOG->PLL_VIDEO = (0x1000); //关闭PLL5
  41. CCM_ANALOG->PLL_ENET = (0x1000); //关闭PLL6
  42. CCM_ANALOG->PLL_USB2 = (0x00); //关闭PLL7
  43. /******************第三层时钟设置--PFD*******************/
  44. /*禁用PLL2 的所有PFD输出*/
  45. CCM_ANALOG->PFD_528 |=(0x80U) ; //关闭PLL2 PFD0
  46. CCM_ANALOG->PFD_528 |=(0x8000U) ; //关闭PLL2 PFD1
  47. // CCM_ANALOG->PFD_528 |=(0x800000U) ; //关闭PLL2 PFD2 ,DDR使用的是该时钟源,关闭后程序不能运行。暂时不关闭
  48. CCM_ANALOG->PFD_528 |=(0x80000000U); //关闭PLL2 PFD3
  49. /*设置PLL2 的PFD输出频率*/
  50. CCM_ANALOG->PFD_528 &= ~(0x3FU); //清零PLL2 PFD0 时钟分频
  51. CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD1 时钟分频
  52. CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD2 时钟分频
  53. CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD3 时钟分频
  54. CCM_ANALOG->PFD_528 |= (0x1B << 0); //设置PLL2 PFD0 输出频率为 352M
  55. CCM_ANALOG->PFD_528 |= (0x10 << 8); //设置PLL2 PFD0 输出频率为 594M
  56. CCM_ANALOG->PFD_528 |= (0x18 << 16); //设置PLL2 PFD0 输出频率为 396M
  57. CCM_ANALOG->PFD_528 |= (0x30 << 24); //设置PLL2 PFD0 输出频率为 198M
  58. /*启用PLL2 的所有PFD输出*/
  59. CCM_ANALOG->PFD_528 &= ~(0x80U) ; //开启PLL2 PFD0
  60. CCM_ANALOG->PFD_528 &= ~(0x8000U) ; //开启PLL2 PFD1
  61. CCM_ANALOG->PFD_528 &= ~(0x800000U) ; //开启PLL2 PFD2
  62. CCM_ANALOG->PFD_528 &= ~(0x80000000U); //开启PLL2 PFD3
  63. /*禁用PLL3 的所有PFD输出*/
  64. CCM_ANALOG->PFD_480 |=(0x80U) ; //关闭PLL3 PFD0
  65. CCM_ANALOG->PFD_480 |=(0x8000U) ; //关闭PLL3 PFD1
  66. CCM_ANALOG->PFD_480 |=(0x800000U) ; //关闭PLL3 PFD2
  67. CCM_ANALOG->PFD_480 |=(0x80000000U); //关闭PLL3 PFD3
  68. /*设置PLL3 的PFD输出频率*/
  69. CCM_ANALOG->PFD_480 &= ~(0x3FU); //清零PLL3 PFD0 时钟分频
  70. CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD1 时钟分频
  71. CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD2 时钟分频
  72. CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD3 时钟分频
  73. CCM_ANALOG->PFD_480 |= (0xC << 0); //设置PLL3 PFD0 输出频率为 720M
  74. CCM_ANALOG->PFD_480 |= (0x10 << 8); //设置PLL3 PFD0 输出频率为 540M
  75. CCM_ANALOG->PFD_480 |= (0x11 << 16); //设置PLL3 PFD0 输出频率为 508.2M
  76. CCM_ANALOG->PFD_480 |= (0x13 << 24); //设置PLL3 PFD0 输出频率为 454.7M
  77. /*启用PLL3 的所有PFD输出*/
  78. CCM_ANALOG->PFD_480 &= ~(0x80U) ; //开启PLL3 PFD0
  79. CCM_ANALOG->PFD_480 &= ~(0x8000U) ; //开启PLL3 PFD1
  80. CCM_ANALOG->PFD_480 &= ~(0x800000U) ; //开启PLL3 PFD2
  81. CCM_ANALOG->PFD_480 &= ~(0x80000000U); //开启PLL3 PFD3
  82. /******************第四层时钟设置--外设****************/
  83. CCM->CSCDR1 &= ~(0x01 << 6); //设置UART选择 PLL3 / 6 = 80MHz
  84. CCM->CSCDR1 &= ~(0x3F); //清零
  85. CCM->CSCDR1 |= ~(0x01 << 0); //设置串口根时钟分频值为1,UART根时钟频率为:80M / (dev + 1) = 40MHz
  86. }

实验现象:烧2次程序,主频不同,灯闪烁频率不同

  1. CCM->CACRR &= ~(0x07 << 0); //清零分频寄存器 不分频
  2. // CCM->CACRR |= (0x07 << 0); // 8分频

P19 第86讲 串口通信实验

硬件原理图

 

相关寄存器:串口时钟、UART配置、收发数据

中断实现uart通信时,一般都使用fifo

代码【与上述分析一致】

  1. #include "uart.h"
  2. void uart_init(void)
  3. {
  4. /*时钟初始化,设置 UART 根时钟,并设置为40MHz*/
  5. CCM->CSCDR1 &= ~(0x01 << 6); //设置UART选择 PLL3 / 6 = 80MHz
  6. CCM->CSCDR1 &= ~(0x3F); //清零
  7. CCM->CSCDR1 |= (0x01 << 0); //设置串口根时钟分频值为1,UART根时钟频率为:80M / (dev + 1) = 40MHz
  8. //禁用 UART1
  9. UART1->UCR1 &= ~UART_UCR1_UARTEN_MASK;
  10. /*软件复位【刚开始工作状态不稳定,复位后就稳定了】*/
  11. UART1->UCR2 &= ~UART_UCR2_SRST_MASK;
  12. while ((UART1->UCR2 & UART_UCR2_SRST_MASK) == 0)
  13. {
  14. }
  15. /*引脚初始化*/
  16. IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX, 0);
  17. IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX, 0x10b0);
  18. IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX, 0);
  19. IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX, 0x10b0);
  20. /*******uart初始化******/
  21. /*设置控制寄存器到默认值*/
  22. UART1->UCR2 |= (1 << 5); //8位数宽度
  23. UART1->UCR2 &= ~(1 << 6); //一位停止位
  24. UART1->UCR2 &= ~(1 << 8); //禁用奇偶校验位
  25. UART1->UCR2 |= (1 << 2); //使能发送
  26. UART1->UCR2 |= (1 << 1); //使能接收
  27. UART1->UCR2 |= (1 << 14); //忽略流控
  28. /* For imx family device, UARTs are used in mode, so that this bit should always be set.*/
  29. UART1->UCR3 |= UART_UCR3_RXDMUXSEL_MASK;
  30. //UART1->UFCR = (UART1->UFCR & ~UART_UFCR_TXTL_MASK) | UART_UFCR_TXTL(1); //设置发送FIFO 阀值
  31. //UART1->UFCR = (UART1->UFCR & ~UART_UFCR_TXTL_MASK) | UART_UFCR_TXTL(1); //设置接收FIFO 阀值
  32. UART1->UCR1 &= ~UART_UCR1_ADBR_MASK; //禁用可变波特率
  33. /*波特率设置方式 1 。 使用官方SDK设置波特率函数*/
  34. UART_SetBaudRate(UART1, 115200, 40000000);
  35. #if 0
  36. /*波特率设置方式 2 。 手动计算,填入寄存器*/
  37. /*设置串口波特率
  38. * Ref Freq时钟 40MHz
  39. * UFCR RFDIV 110 0x06 7分频 5.714MHz
  40. * BaudRate 115200bps
  41. * UBMR 31-1 = 0x09
  42. * UBIR 10-1 = 0x1E
  43. */
  44. UART1->UFCR &= ~(0x07 << 7); //清零分频值
  45. UART1->UFCR |= (0x06 << 7); //设置分频值,40MHz /7 = 5.714MHz
  46. UART1->UBIR = 0x09;
  47. UART1->UBMR = 0x1E;
  48. #endif
  49. /*开启串口*/
  50. UART1->UCR1 |= UART_UCR1_UARTEN_MASK;
  51. }
  52. /*!
  53. * 功能:官方SDK 串口字符串读取函数
  54. * @brief Reads the receiver register.
  55. *
  56. * This function is used to read data from receiver register.
  57. * The upper layer must ensure that the receiver register is full or that
  58. * the RX FIFO has data before calling this function.
  59. *
  60. * @param base UART peripheral base address.
  61. * @return Data read from data register.
  62. */
  63. static inline uint8_t UART_ReadByte(UART_Type *base)
  64. {
  65. return (uint8_t)((base->URXD & UART_URXD_RX_DATA_MASK) >> UART_URXD_RX_DATA_SHIFT);
  66. }
  67. /*函数功能:串口接收函数
  68. *参数: base,指定串口。data,保存接收到的数据。 length,要接收的数据长度
  69. *
  70. */
  71. void UART_ReadBlocking(UART_Type *base, uint8_t *data, uint8_t length)
  72. {
  73. while (length--)
  74. {
  75. /* 等待接收完成 */
  76. while (!(base->USR2 & UART_USR2_RDR_MASK))
  77. {
  78. }
  79. /*读取接收到的数据 */
  80. *(data++) = UART_ReadByte(base);
  81. }
  82. }
  83. /*!
  84. * 功能:官方SDK 串口发送函数
  85. * 参数:base,指定串口。data,指定要发送的字节
  86. * This function is used to write data to transmitter register.
  87. * The upper layer must ensure that the TX register is empty or that
  88. * the TX FIFO has room before calling this function.
  89. */
  90. static inline void UART_WriteByte(UART_Type *base, uint8_t data)
  91. {
  92. base->UTXD = data & UART_UTXD_TX_DATA_MASK;
  93. }
  94. /*
  95. *功能:官方SDK 串口字符串发送函数
  96. *参数说明:
  97. */
  98. void UART_WriteBlocking(UART_Type *base, const uint8_t *data, uint8_t length)
  99. {
  100. while (length--)
  101. {
  102. /* Wait for TX fifo valid.
  103. * This API can only ensure that the data is written into the data buffer but can't
  104. * ensure all data in the data buffer are sent into the transmit shift buffer.
  105. */
  106. while (!(base->USR2 & UART_USR2_TXDC_MASK))
  107. {
  108. }
  109. UART_WriteByte(base, *(data++));
  110. }
  111. }
  1. # include "common.h"
  2. #include "led.h"
  3. #include "button.h"
  4. #include "interrupt.h"
  5. #include "clock.h"
  6. #include "uart.h"
  7. uint8_t button_status=0;
  8. char g_charA = 'A'; //存储在 .data段
  9. char g_charB = 'A'; //存储在 .data段
  10. /*提示字符串*/
  11. uint8_t txbuff[] = "Uart polling example\r\nBoard will send back received characters\r\n";
  12. int main()
  13. {
  14. //用于暂存串口收到的字符
  15. uint8_t ch;
  16. /*系统时钟初始化*/
  17. system_clock_init();
  18. /*GIC中断和中断向量表初始化*/
  19. irq_init();
  20. /*初始化led灯和按键*/
  21. rgb_led_init();
  22. /*串口初始化*/
  23. uart_init();
  24. /*发送提示字符串*/
  25. UART_WriteBlocking(UART1, txbuff, sizeof(txbuff) - 1);
  26. red_led_on; //红灯亮,提示程序运行中
  27. while (1)
  28. {
  29. UART_ReadBlocking(UART1, &ch, 1);
  30. UART_WriteBlocking(UART1, &ch, 1);
  31. }
  32. return 0;

Makefile修改:gcc除法库

代码效果【上电发送提示字符,随后收什么发什么】

 

P20 第87讲 LCD显示原理

RGB接口三原色传输

硬件原理图

基本原理:视频即多帧图片、图片逐行显示


时序帧同步行同步、帧开始/结束缓冲时间


参数:看数据手册、RGB888 565、分辨率、像素时钟

P21 第88讲 LCD显示实验

相关寄存器

代码讲解:引脚配置、时钟配置、LCD配置

7种纯色循环显示

  1. # include "common.h"
  2. #include "led.h"
  3. #include "button.h"
  4. #include "interrupt.h"
  5. #include "clock.h"
  6. #include "uart.h"
  7. #include "lcd.h"
  8. uint8_t button_status=0;
  9. char g_charA = 'A'; //存储在 .data段
  10. char g_charB = 'A'; //存储在 .data段
  11. /*提示字符串*/
  12. uint8_t txbuff[] = "Uart polling example\r\nBoard will send back received characters\r\n";
  13. int main()
  14. {
  15. //用于暂存串口收到的字符
  16. uint8_t ch;
  17. /*lcd显存编号*/
  18. uint32_t frameBufferIndex = 0;
  19. /*系统时钟初始化*/
  20. system_clock_init();
  21. /*GIC中断和中断向量表初始化*/
  22. irq_init();
  23. /*初始化led灯和按键*/
  24. rgb_led_init();
  25. /*串口初始化*/
  26. uart_init();
  27. /*发送提示字符串*/
  28. UART_WriteBlocking(UART1, txbuff, sizeof(txbuff) - 1);
  29. /*初始 lcdif 引脚*/
  30. lcdif_pin_config();
  31. /*初始化时钟*/
  32. lcdif_clock_init();
  33. /*初始化 lcd属性和中断*/
  34. lcd_property_Init();
  35. red_led_on;
  36. while (1)
  37. {
  38. frameBufferIndex ^= 1U; //异或,相当于取反。1U表示无符号整数1
  39. APP_FillFrameBuffer(s_frameBuffer[frameBufferIndex]);
  40. LCDIF->NEXT_BUF = (uint32_t)s_frameBuffer[frameBufferIndex];
  41. /* 等待上一个图片刷新完成 Wait for previous frame complete. */
  42. while (!s_frameDone);
  43. s_frameDone = false;
  44. delay(0xFFFF);
  45. }
  46. return 0;
  1. #include "lcd.h"
  2. #include "interrupt.h"
  3. /*定义 elcdf 缓冲区[2--两张图片 APP_IMG_HEIGHT--列像素 APP_IMG_WIDTH--行像素]*/
  4. uint32_t s_frameBuffer[2][APP_IMG_HEIGHT][APP_IMG_WIDTH];
  5. uint8_t s_frameDone = false;
  6. /* elcdif 显示接口外部引脚初始化
  7. *
  8. */
  9. void lcdif_pin_config(void)
  10. {
  11. IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK, 0U);
  12. IOMUXC_SetPinConfig(IOMUXC_LCD_CLK_LCDIF_CLK, 0xB9);
  13. IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0U);
  14. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0xB9);
  15. IOMUXC_SetPinMux(IOMUXC_LCD_DATA01_LCDIF_DATA01, 0U);
  16. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA01_LCDIF_DATA01, 0xB9);
  17. IOMUXC_SetPinMux(IOMUXC_LCD_DATA02_LCDIF_DATA02, 0U);
  18. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA02_LCDIF_DATA02, 0xB9);
  19. IOMUXC_SetPinMux(IOMUXC_LCD_DATA03_LCDIF_DATA03, 0U);
  20. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA03_LCDIF_DATA03, 0xB9);
  21. IOMUXC_SetPinMux(IOMUXC_LCD_DATA04_LCDIF_DATA04, 0U);
  22. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA04_LCDIF_DATA04, 0xB9);
  23. IOMUXC_SetPinMux(IOMUXC_LCD_DATA05_LCDIF_DATA05, 0U);
  24. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA05_LCDIF_DATA05, 0xB9);
  25. IOMUXC_SetPinMux(IOMUXC_LCD_DATA06_LCDIF_DATA06, 0U);
  26. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA06_LCDIF_DATA06, 0xB9);
  27. IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_LCDIF_DATA07, 0U);
  28. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_LCDIF_DATA07, 0xB9);
  29. IOMUXC_SetPinMux(IOMUXC_LCD_DATA08_LCDIF_DATA08, 0U);
  30. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA08_LCDIF_DATA08, 0xB9);
  31. IOMUXC_SetPinMux(IOMUXC_LCD_DATA09_LCDIF_DATA09, 0U);
  32. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA09_LCDIF_DATA09, 0xB9);
  33. IOMUXC_SetPinMux(IOMUXC_LCD_DATA10_LCDIF_DATA10, 0U);
  34. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA10_LCDIF_DATA10, 0xB9);
  35. IOMUXC_SetPinMux(IOMUXC_LCD_DATA11_LCDIF_DATA11, 0U);
  36. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA11_LCDIF_DATA11, 0xB9);
  37. IOMUXC_SetPinMux(IOMUXC_LCD_DATA12_LCDIF_DATA12, 0U);
  38. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA12_LCDIF_DATA12, 0xB9);
  39. IOMUXC_SetPinMux(IOMUXC_LCD_DATA13_LCDIF_DATA13, 0U);
  40. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA13_LCDIF_DATA13, 0xB9);
  41. IOMUXC_SetPinMux(IOMUXC_LCD_DATA14_LCDIF_DATA14, 0U);
  42. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA14_LCDIF_DATA14, 0xB9);
  43. IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_LCDIF_DATA15, 0U);
  44. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_LCDIF_DATA15, 0xB9);
  45. IOMUXC_SetPinMux(IOMUXC_LCD_DATA16_LCDIF_DATA16, 0U);
  46. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA16_LCDIF_DATA16, 0xB9);
  47. IOMUXC_SetPinMux(IOMUXC_LCD_DATA17_LCDIF_DATA17, 0U);
  48. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA17_LCDIF_DATA17, 0xB9);
  49. IOMUXC_SetPinMux(IOMUXC_LCD_DATA18_LCDIF_DATA18, 0U);
  50. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA18_LCDIF_DATA18, 0xB9);
  51. IOMUXC_SetPinMux(IOMUXC_LCD_DATA19_LCDIF_DATA19, 0U);
  52. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA19_LCDIF_DATA19, 0xB9);
  53. IOMUXC_SetPinMux(IOMUXC_LCD_DATA20_LCDIF_DATA20, 0U);
  54. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA20_LCDIF_DATA20, 0xB9);
  55. IOMUXC_SetPinMux(IOMUXC_LCD_DATA21_LCDIF_DATA21, 0U);
  56. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA21_LCDIF_DATA21, 0xB9);
  57. IOMUXC_SetPinMux(IOMUXC_LCD_DATA22_LCDIF_DATA22, 0U);
  58. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA22_LCDIF_DATA22, 0xB9);
  59. IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_LCDIF_DATA23, 0U);
  60. IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_LCDIF_DATA23, 0xB9);
  61. IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0U);
  62. IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0xB9);
  63. IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0U);
  64. IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0xB9);
  65. IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0U);
  66. IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0xB9);
  67. IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0U);
  68. IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08,0xB9); /* 背光BL引脚 */
  69. /*设置GPIO1_08为输出模式*/
  70. GPIO1->GDIR |= (1<<8);
  71. /*设置GPIO1_08输出电平为低电平【不打开背光灯】*/
  72. GPIO1->DR |= (0<<8);
  73. }
  74. /*初始化 elcdf 的时钟
  75. */
  76. void lcdif_clock_init(void)
  77. {
  78. /*设置 PLL5 的输出时钟*/
  79. CCM_ANALOG->PLL_VIDEO_NUM &= (0x3 << 30); //清零PLL 分数分频的分子寄存器
  80. CCM_ANALOG->PLL_VIDEO_DENOM &= (0x3 << 30); //清零PLL 分数分频的分母寄存器
  81. /*
  82. * 设置时钟分频
  83. *
  84. * ------------------------------------------------------------------------
  85. * | 分频数 | PLL_VIDEO[POST_DIV_SELECT] | MISC2[VIDEO_DIV] |
  86. * ------------------------------------------------------------------------
  87. * | 1 | 2 | 0 |
  88. * ------------------------------------------------------------------------
  89. * | 2 | 1 | 0 |
  90. * ------------------------------------------------------------------------
  91. * | 4 | 2 | 3 |
  92. * ------------------------------------------------------------------------
  93. * | 8 | 1 | 3 |
  94. * ------------------------------------------------------------------------
  95. * | 16 | 0 | 3 |
  96. * ------------------------------------------------------------------------
  97. */
  98. CCM_ANALOG->PLL_VIDEO = 0;
  99. CCM_ANALOG->PLL_VIDEO &= ~(0x3 << 19); // 清零PLL_VIDEO[POST_DIV_SELECT]
  100. CCM_ANALOG->PLL_VIDEO |= (0x01 << 19); //设置分频系数为2
  101. CCM_ANALOG->MISC2 &= ~(0xC0000000); //清零VIDEO_DIV位
  102. CCM_ANALOG->MISC2 |= (0x3 << 30);// 配合CCM_ANALOG->PLL_VIDEO寄存器设置时钟分频
  103. CCM_ANALOG->PLL_VIDEO &= ~(0x7F); // 清零时钟分频
  104. CCM_ANALOG->PLL_VIDEO |= (0x1F); //设置时钟分频为 31(十进制)
  105. CCM_ANALOG->PLL_VIDEO |= 1 << 13; //使能PLL5时钟输出
  106. /*等待设置生效*/
  107. while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0)
  108. {
  109. }
  110. /*设置从PLL5 到 elcdf 根时钟所经过的时钟选择和时钟分频寄存器*/
  111. CCM->CSCDR2 &= ~(0x07 << 15); //清零
  112. CCM->CSCDR2 |= (0x02 << 15); //设置CSCDR2[LCDIF1_PRE_CLK_SEL] 选择 PLL5 输出时钟
  113. CCM->CSCDR2 &= ~(0x07 << 12); //清零
  114. CCM->CSCDR2 |= (0x01 << 12); //设置 CSCDR2[LCDIF1_PRED]时钟分频值
  115. CCM->CBCMR &= ~(0x07 << 23); //清零CBCMR[LCDIF1_PODF] 时钟分频值
  116. CCM->CBCMR |= (0x01 << 23);
  117. CCM->CSCDR2 &= ~(0x07 << 9); //清零
  118. CCM->CSCDR2 |= (0x00 << 9); //选择 CSCDR2[LCDIF1_CLK_SEL] 选择 PLL5 输出时钟
  119. }
  120. /* 软复位lcd【使用LCD_RST复位则为硬复位】 */
  121. void ELCDIF_Reset(void)
  122. {
  123. LCDIF->CTRL = 1<<31;
  124. delay(100);
  125. LCDIF->CTRL = 0<<31;
  126. /*设置GPIO1_08输出电平为高电平,打开背光*/
  127. GPIO1->DR |= (1<<8);
  128. }
  129. /*将 lcd 初始化为 rgb 888 模式,并设置lcd中断c
  130. */
  131. void lcd_property_Init(void)
  132. {
  133. /* Reset. */
  134. ELCDIF_Reset();
  135. LCDIF->CTRL &= ~(0x300); //根据颜色格式设置 CTRL 寄存器 颜色个事为RGB888
  136. LCDIF->CTRL |= (0x3 << 8);
  137. LCDIF->CTRL &= ~(0xC00); //设置数据宽度为24位宽
  138. LCDIF->CTRL |= (0x3 << 10);
  139. LCDIF->CTRL |= (0x20000); // 选择 RGB 模式
  140. LCDIF->CTRL |= (0x80000); // 选择 RGB 模式 开启显示
  141. LCDIF->CTRL |= (0x20); //设置elcdf接口为主模式
  142. LCDIF->CTRL1 &= ~(0xF0000); //清零32位数据有效位
  143. LCDIF->CTRL1 |= (0x07 << 16); // 设置32位有效位的低24位有效。
  144. // LCDIF->TRANSFER_COUNT = 0;//清零分辨率设置寄存器
  145. LCDIF->TRANSFER_COUNT |= APP_IMG_HEIGHT << 16; //设置一列 像素数 480
  146. LCDIF->TRANSFER_COUNT |= APP_IMG_WIDTH << 0; //设置一行 像素数 800
  147. LCDIF->VDCTRL0 |= LCDIF_VDCTRL0_ENABLE_PRESENT_MASK; //生成使能信号
  148. LCDIF->VDCTRL0 |= LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT_MASK; //设置VSYNC周期 的单位为显示时钟的时钟周期
  149. LCDIF->VDCTRL0 |= LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT_MASK; //设置VSYNC 脉冲宽度的单位为显示时钟的时钟周期
  150. LCDIF->VDCTRL0 |= (1 << 24); //设置 数据使能信号的有效电平为高电平
  151. LCDIF->VDCTRL0 &= ~(0x8000000); //设置 VSYNC 有效电平为低电平
  152. LCDIF->VDCTRL0 &= ~(0x4000000); //设置HSYNC有效电平为低电平
  153. LCDIF->VDCTRL0 |= (0x2000000); // 设置在时钟的下降沿输出数据,在时钟的上升沿捕获数据。
  154. LCDIF->VDCTRL0 |= APP_VSW;
  155. // 以显示时钟为单位的周期。
  156. LCDIF->VDCTRL1 = APP_VSW + APP_IMG_HEIGHT + APP_VFP + APP_VBP; //设置VSYNC 信号周期
  157. LCDIF->VDCTRL2 |= (APP_HSW << 18); //HSYNC 信号有效电平长度
  158. LCDIF->VDCTRL2 |= (APP_HFP + APP_HBP + APP_IMG_WIDTH + APP_HSW); //HSYNC 信号周期
  159. LCDIF->VDCTRL3 |= (APP_HBP + APP_HSW) << 16;
  160. LCDIF->VDCTRL3 |= (APP_VBP + APP_VSW);
  161. LCDIF->VDCTRL4 |= (0x40000);
  162. LCDIF->VDCTRL4 |= (APP_IMG_WIDTH << 0);
  163. LCDIF->CUR_BUF = (uint32_t)s_frameBuffer[0];
  164. LCDIF->NEXT_BUF = (uint32_t)s_frameBuffer[0];
  165. /*注册lcd中断函数*/
  166. system_register_irqhandler(LCDIF_IRQn, (system_irq_handler_t)(uint32_t)APP_LCDIF_IRQHandler, NULL); // 设置中断服务函数
  167. /*开启中断*/
  168. GIC_EnableIRQ(LCDIF_IRQn);
  169. /*使能 elcdf 一帧传输完成中断*/
  170. LCDIF->CTRL1_SET |= (0x2000);
  171. /*开启 elcdf 开始显示*/
  172. LCDIF->CTRL_SET |= 0x1;
  173. LCDIF->CTRL_SET |= (1 << 17);
  174. }
  175. void APP_FillFrameBuffer(uint32_t frameBuffer[APP_IMG_HEIGHT][APP_IMG_WIDTH])
  176. {
  177. /* Background color. 【黑色】*/
  178. static const uint32_t bgColor = 0U;
  179. /* Foreground color. */
  180. static uint8_t fgColorIndex = 0U;
  181. // static uint16_t lowerRightX = (APP_IMG_WIDTH - 1U) / 2U; //例程代码只在屏幕左上角1/4显示
  182. // static uint16_t lowerRightY = (APP_IMG_HEIGHT - 1U) / 2U;
  183. static uint16_t lowerRightX = (APP_IMG_WIDTH - 1U); //改为全屏显示
  184. static uint16_t lowerRightY = (APP_IMG_HEIGHT - 1U);
  185. //对应7种颜色
  186. static const uint32_t fgColorTable[] = {0x000000FFU, 0x0000FF00U, 0x0000FFFFU, 0x00FF0000U,
  187. 0x00FF00FFU, 0x00FFFF00U, 0x00FFFFFFU};
  188. uint32_t fgColor = fgColorTable[fgColorIndex];
  189. uint32_t i, j;
  190. /* Background color. 【全屏黑色】*/
  191. for (i = 0; i < APP_IMG_HEIGHT; i++){
  192. for (j = 0; j < APP_IMG_WIDTH; j++) {
  193. frameBuffer[i][j] = bgColor;
  194. }
  195. }
  196. /* Foreground color. */
  197. for (i = 0; i < lowerRightY; i++){
  198. for (j = 0; j < lowerRightX; j++) {
  199. frameBuffer[i][j] = fgColor;
  200. }
  201. }
  202. if(fgColorIndex == ARRAY_SIZE(fgColorTable))
  203. fgColorIndex = 0;
  204. else
  205. fgColorIndex++;
  206. }
  207. void APP_LCDIF_IRQHandler(void)
  208. {
  209. uint32_t intStatus = 0;
  210. /*获取传输完成中断的状态,*/
  211. intStatus = ((LCDIF->CTRL1) & (1 <<9));
  212. /*清除 1 帧传输完成中断标志位*/
  213. LCDIF->CTRL1_CLR = (1 << 9);
  214. if (intStatus)
  215. {
  216. s_frameDone = true; //传输完成后,全局变量为true
  217. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/711368
推荐阅读
相关标签
  

闽ICP备14008679号