从官网下载并安装TM4C123Gxx的SDK,会在C:\ti目录下得到一个TivaWare_C_Series-2.2.0.295,这就是关键的代码,这里挑出几个常用的文件夹来说一说
![](https://img-blog.csdnimg.cn/872d1bffa1f34bf99fd1afd7167ca8c2.png)
个人学习首先肯定是examples,里面有基于评估板的工程示例"boards",基本外设驱动示例"peripherals",还有一个空白工程模板"project"
这里需要注意的是,project中的keil工程还是uv4版本,使用keil5打开会导致uv5不能正常识别已经安装pack的单片机型号,具体表现为打开后弹窗"the project references devices,files or libraries that are not installed"和"error:device not found",并且打开魔术棒的Device也看不到已经安装pack的单片机型号。建议使用一个例如STM32的keil5工程让keil正常工作,然后创建一个新工程再把文件添加进去,以此可以确保后续debug的顺利。
一年前研究TM4的时候,只是看example,进入了一个误区,TI的外设使用的都是一个编译后的lib文件,看不到每个外设驱动API具体实现,曾经一度以为TI对单片机驱动库闭源了,很痛苦搞了很久才发现代码文件夹下还有个driverlib文件夹,打开里面就是编译出外设驱动库lib文件的工程,外设API的源代码在里面都有。TI编译成lib库可以减小工程的体积,加快编译速度,也可以避免改变优化等级带来的bug。点赞。
![](https://img-blog.csdnimg.cn/bf5f197d692f4844bac54d1728252751.png)
TI还提供了库函数的API手册“TivaWare™ Peripheral Driver Library USER’S GUIDE”,里面详细介绍了库函数每个API的作用和输入输出参数,配合chatGPT翻译体验极佳。
![](https://img-blog.csdnimg.cn/6f094f9ca82845b8878ed93547e1e495.png)
当然折腾过程中也还是遇到了坑,这篇文章主要就是记录遇到的坑
首先第一个坑就是SSI(SPI)例程中的串口初始化代码居然会卡死,没有修改代码的情况下
void InitConsole(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); //卡死位置
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTStdioConfig(0, 115200, 16000000);
}
这里删除了他大片的注释便于观察,可以看到初始化过程非常清晰自然没有任何问题,但实测运行的时候到"UARTClockSourceSet"这句就会直接卡死,只要在前面加上一个等效于3周期的delay就行了,具体原因不详。去翻看了这个函数的源代码发现里面根本没有while,大概是直接导致硬件错误了。很奇怪
第二个坑:系统时钟配置函数有两个
void SysCtlClockSet(uint32_t ui32Config);
![](https://img-blog.csdnimg.cn/a1941d5055c34d81902fb19165098870.png)
![](https://img-blog.csdnimg.cn/24d4d5258b174246adfde2509f9d9288.png)
uint32_t SysCtlClockFreqSet(uint32_t ui32Config, uint32_t ui32SysClock);
![](https://img-blog.csdnimg.cn/2f5614c84a164abd9d0f0b805546c3d3.png)
![](https://img-blog.csdnimg.cn/f2dca539e10148e09c95b28644721646.png)
![](https://img-blog.csdnimg.cn/d6e43431d52844439ac637b133fca4b1.png)
从函数的申明到手册的描述,我以为SysCtlClockFreqSet()包含了SysCtlClockSet(),大部分功能是重复的,就直接把例程里本来用的SysCtlClockFreqSet()改了个参数
SysCtlClockFreqSet(SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320, 80000000);
使用外部晶振和PLL,PLL频率320M,系统主频80M。看着没有任何问题,我就信心满满地搞SPI,把SPI波特率拉满到40M,程序卡死,降低到10M,卡死,再降低,最后发现SPI最高只能到8M。看框图发现系统主频到SPI时钟有一个分频,但那个分频找不到操作的函数,进debug看寄存器发现SPI确实没有分频,速度已经最大了。折腾了一两个小时才想到查一下主频,好家伙,系统时钟只有16M。
又回头来查系统时钟初始化,但这个配置函数想破脑袋我也想不明白有啥问题。实在没办法了想起example,去找到了RCC例程,才发现他使用外部晶振调用的是SysCtlClockSet(),使用内部振荡器才用SysCtlClockFreqSet()。
SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
这么一搞,主频到了80M,SPI也40M轻松跑起。
看似简单的成功背后都是痛苦的纠错。