概述
S32K系列芯片开发时,尽管官方提供了SDK并且目前已经更新至4.02版本,并有Processor expert一键配置,时钟,外设,中断等等组件经过配置之后,可以生成驱动函数,一键拖动调用,一部分需要手动填充入参。即使这样在开发过程中不明所以,新项目也仅仅是参考移植,没有增长。所以打算对每个外设做一个手写版本,并作记录。
时钟
S32K的时钟比较多,FIRC,SIRC,SOSC,LPO,RTC。在S32K1XXX系列中没有PLL,通过配置使能相关寄存器,达到想要的时钟源及时钟分频,但看参考手册不够直观,S32DS提供了明了的始终结构,对开发很有帮助 上图为运行状态下的时钟图 上图为外设的时钟选择 以上是VCCR的时钟分配
参考以上时钟图可以很清楚的知道需要配置哪些寄存器,始终结构是怎样的组成,但是一旦时钟配置有误,会出现不能驱动外设的情况,具体在debug模式下可以查看该时钟寄存器的VLD状态,如果配置没有问题,该位置位。我在驱动串口时,发现发送缓冲区一直处于full状态,查了好久才发现SOSCVLD位没有置位,在修改串口时钟源为SIRC之后,可以发送数据。
时钟初始化代码
#include "clockdriver.h"
static void ConfigFIRC(void)
{
SCG->FIRCCSR &= (uint32_t)(~SCG_FIRCCSR_FIRCEN_MASK);
SCG->FIRCDIV = SCG_FIRCDIV_FIRCDIV1(1) | SCG_FIRCDIV_FIRCDIV2(1);
SCG->FIRCCFG = SCG_FIRCCFG_RANGE(0);
while(SCG->FIRCCSR & SCG_FIRCCSR_LK_MASK);
SCG->FIRCCSR = SCG_FIRCCSR_FIRCEN(1);
while((SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK) >> SCG_FIRCCSR_FIRCVLD_SHIFT != 1);
}
static void ConfigSIRC(void)
{
SCG->SIRCCSR &= (uint32_t)(~SCG_SIRCCSR_SIRCEN_MASK);
SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV1(1) | SCG_SIRCDIV_SIRCDIV2(1);
SCG->SIRCCFG = SCG_SIRCCFG_RANGE(1);
while(SCG->SIRCCSR & SCG_SIRCCSR_LK_MASK);
SCG->SIRCCSR = SCG_SIRCCSR_SIRCEN(1);
while((SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK) >> SCG_SIRCCSR_SIRCVLD_SHIFT != 1);
}
static void ConfigSOSC(void)
{
SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV1(1) | SCG_SOSCDIV_SOSCDIV2(1);
SCG->SOSCCFG = SCG_SOSCCFG_RANGE(2) | SCG_SOSCCFG_HGO(0) | SCG_SOSCCFG_EREFS(1);
while(SCG->SOSCCSR & SCG_SOSCCSR_LK_MASK);
SCG->SOSCCSR = SCG_SOSCCSR_SOSCEN(1);
while((SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) >> SCG_SOSCCSR_SOSCVLD_SHIFT != 1);
}
static void ConfigLPO(void)
{
SIM->LPOCLKS = SIM_LPOCLKS_LPO32KCLKEN(1);
SIM->LPOCLKS = SIM_LPOCLKS_LPO32KCLKEN(1);
SIM->LPOCLKS = SIM_LPOCLKS_LPOCLKSEL(0);
SIM->LPOCLKS = SIM_LPOCLKS_RTCCLKSEL(3);
}
static void ConfigRunMode(void)
{
SCG->RCCR = SCG_RCCR_SCS(3) | SCG_RCCR_DIVCORE(0) | SCG_RCCR_DIVSLOW(1) | SCG_RCCR_DIVBUS(0);
while((SCG->CSR & SCG_CSR_SCS_MASK) != (uint32_t)0x03000000);
}
static void ConfigVLPRMode(void)
{
SCG->VCCR = SCG_VCCR_SCS(2) | SCG_VCCR_DIVCORE(1) | SCG_VCCR_DIVBUS(0) | SCG_VCCR_DIVSLOW(3);
}
void ConfigClkOut(void)
{
SCG->CLKOUTCNFG |= SCG_CLKOUTCNFG_CLKOUTSEL(1);
SIM->CHIPCTL &= ~SIM_CHIPCTL_CLKOUTEN_MASK;
SIM->CHIPCTL &= ~SIM_CHIPCTL_CLKOUTSEL_MASK;
SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTSEL(2);
SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTDIV(0);
SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTEN(1);
}
void ClockInit(void)
{
(void)ConfigFIRC();
(void)ConfigSIRC();
(void)ConfigSOSC();
(void)ConfigRunMode();
}
串口代码只写了发送,使能了FIFO,未使用中断
void Uart0Init(void)
{
PCC->PCCn[PCC_PORTC_INDEX] |= PCC_PCCn_CGC(1);
PORTC->PCR[2] &=PORT_PCR_MUX_MASK;
PORTC->PCR[2] |= PORT_PCR_MUX(4);
PORTC->PCR[3] &=PORT_PCR_MUX_MASK;
PORTC->PCR[3] |= PORT_PCR_MUX(4);
PCC->PCCn[PCC_LPUART0_INDEX] &= ~PCC_PCCn_CGC_MASK;
PCC->PCCn[PCC_LPUART0_INDEX] &= ~PCC_PCCn_PCS_MASK;
PCC->PCCn[PCC_LPUART0_INDEX] |= PCC_PCCn_PCS(1);
PCC->PCCn[PCC_LPUART0_INDEX] |= PCC_PCCn_CGC(1);
LPUART0->CTRL &= ~LPUART_CTRL_TE_MASK;
LPUART0->CTRL &= ~LPUART_CTRL_RE_MASK;
LPUART0->BAUD |= LPUART_BAUD_SBR(52);
LPUART0->BAUD |= LPUART_BAUD_OSR(15);
LPUART0->CTRL |= LPUART_CTRL_TE_MASK;
LPUART0->CTRL |= LPUART_CTRL_RE_MASK;
LPUART0->FIFO = 0x0003C000;
LPUART0->FIFO |= LPUART_FIFO_TXFE_MASK;
LPUART0->FIFO |= LPUART_FIFO_RXFE_MASK;
LPUART0->WATER = 0x00000000;
LPUART0->WATER |= LPUART_WATER_TXWATER(3);
LPUART0->WATER |= LPUART_WATER_RXWATER(3);
while((LPUART0->CTRL & LPUART_CTRL_TE_MASK) != LPUART_CTRL_TE_MASK);
}
uint8_t UartSendChar(uint8_t buff)
{
int count = 0;
while(((LPUART0->STAT & LPUART_STAT_TDRE_MASK) != LPUART_STAT_TDRE_MASK) && count++ < 0xFFFF);
if(count >= 0xFFFF)
return 0;
LPUART0->DATA = buff;
return 1;
}
uint8_t UartSendString(uint8_t *buff,uint8_t len)
{
uint8_t i;
for(i = 0;i<len;i++)
{
if(!UartSendChar(buff[i]))
break;
}
if(i < len)
return 0;
else
return 1;
}
主函数如下
#include "Cpu.h"
#include "include.h"
uint8_t Buff2Send[3] = {0x55,0xAA,0xCC};
volatile uint32_t clocktick = 0;
volatile int exit_code = 0;
#define MAXVALUE 50000
int main(void)
{
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT();
#endif
wdog_stop();
ClockInit();
Uart0Init();
for(;;)
{
clocktick++;
if(clocktick > MAXVALUE)
{
UartSendString(Buff2Send,3);
clocktick = 0;
}
}
#ifdef PEX_RTOS_START
PEX_RTOS_START();
#endif
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
}
利用示波器或者逻辑分析仪可以验证波特率和发送数据是否正常。 看门狗在缺省状态下为开启,所以第一步需要禁用,这也是一个坑
|