硬件环境:AC7801x 通用开发板 ATC-LINK
软件环境:keil 5.23
上一章节完成了clock,让芯片运行在48M PLL下,这次我们主要完成下面三个工作:
1,让延时更精确,将采用systick进行延时,实现延时功能
2,增加休眠唤醒,让芯片可以进入休眠以及唤醒
3,增加CAN模块的收发功能
一,使用systick进行延时,可直接参照驱动中的实现。
- /*!
- * [url=home.php?mod=space&uid=247401]@brief[/url] delay until the syctick count tick to 0
- *
- * @param[in] tick : systick count value
- * [url=home.php?mod=space&uid=266161]@return[/url] none
- */
- static void SysTickDelay(uint32_t tick)
- {
- __IO uint32_t tickFlag = 0;
- SysTick->LOAD = tick - 1;
- SysTick->VAL = 0x00;
- SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
- do
- {
- tickFlag = SysTick->CTRL;
- } while(!(tickFlag & SysTick_CTRL_COUNTFLAG_Msk));
- SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
- SysTick->VAL = 0X00;
- }
- /*!
- * [url=home.php?mod=space&uid=247401]@brief[/url] Repeatlly delay the ticks for the given times
- *
- * @param[in] param : times, the times of delay the tick
- * @param[in] param : tick, each tick to delay
- * [url=home.php?mod=space&uid=266161]@return[/url] none
- */
- static void SysTickRepeatDelay(uint32_t times, uint32_t tick)
- {
- uint32_t i = 0;
- for (i = 0; i < times; i++)
- {
- SysTickDelay(tick);
- }
- }
- /*!
- * @brief delay us
- *
- * @param[in] param : us, us for delay
- * @return none
- */
- void udelay(uint32_t us)
- {
- uint32_t tick = us * s_facus;
- SysTickRepeatDelay(tick / MAX_SYSTICK_COUNT, MAX_SYSTICK_COUNT);
- SysTickDelay(tick % MAX_SYSTICK_COUNT);
- }
- /*!
- * @brief delay ms
- *
- * @param[in] param : ms, us for delay
- * @return none
- */
- void mdelay(uint32_t ms)
- {
- uint32_t tick = ms * s_facms;
- SysTickRepeatDelay(tick / MAX_SYSTICK_COUNT, MAX_SYSTICK_COUNT);
- SysTickDelay(tick % MAX_SYSTICK_COUNT);
- }
二,芯片进入stop模式
此处设置stop1,同时使能spm,关闭LVD是为了让功耗更低,第三行似乎是内部的一些操作,也保留了下来。
最后就是arm内核的休眠操作了。
- void sysStop(void)
- {
- MODIFY_REG32(SPM->PWR_MGR_CFG0, SPM_PWR_MGR_CFG0_SLEEP_MODE_Msk, SPM_PWR_MGR_CFG0_SLEEP_MODE_Pos, 1); ///<set stop 1 mode
- SET_BIT32(SPM->PWR_MGR_CFG0, SPM_PWR_MGR_CFG0_PWR_EN_Msk); ///<enable spm
- MODIFY_MEM32(REG_PORLPVD_CFG0_ADDR, LOW_POWER_CFG_MASK, LOW_POWER_CFG_START_BIT, LOW_POWER_CFG_VALUE);
- CLEAR_BIT32(SPM->PWR_MGR_CFG0, SPM_PWR_MGR_CFG0_EN_DPWRLVD_Msk); ///<disable LVD
-
- /* Set the SLEEPDEEP bit to enable deep sleep mode (STOP) */
- SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
-
- // If using KEIL's uVision, use the CMSIS intrinsic
- __wfi();
- }
当然,在进入休眠前,少不了要使能一些唤醒,否则就起不来了,所以在外层再封装一个函数,此处使能了GPIO以及CAN唤醒
- void Mcu_GotoLowPower(void)
- {
- SPM->EN_PERIPH_WAKEUP |= SPM_EN_PERIPH_WAKEUP_CAN0_Msk | SPM_EN_PERIPH_WAKEUP_GPIO_Msk; ///<enable wakeup
- sysStop();
-
- }
三,can实现,对于can实现的具体就不细说了,对于一般的使用来说,can确实没有太多东西需要初始化的。在can.h文件中实现了如下接口。
- typedef struct _can_msg
- {
- uint32_t ID;
- uint32_t DLC:4; /*!< Data length code */
- uint32_t FDF:1; /*!< FD format indicator */
- uint32_t IDE:1; /*!< Identifier extension */
- uint32_t reserved:26;
- uint8_t DATA[64]; /*!< Data must 4bytes align*/
- }CanMsgType;
-
- extern void Can_Init(void);
-
- extern void Can_DeInit(void);
- extern int Can_Transmit(CanMsgType *canMsg);
- extern int Can_Receive(CanMsgType *canMsg);
整体工程实现过程中遇到如下问题:
1,can模块DATA域必须4字节对齐
在cortex-m0+中是不支持非对齐访问的,而can模块的RBUF和TBUF又都是按照4字节访问,所以在访问时我们需要将我们定义的结构体中的DATA成员转为uint32,如果DATA未四字节对齐,将会导致非对齐访问错误而进入hardfault
- CANx->TBUF.DATA[i>>2] = *(uint32_t *)(&canMsg->DATA[i]);
所以在定义can结构体时,需要在前面填充,以确保声明的DATA[64]起始地址是4字节对齐的
2,can模块初始化时,部分寄存器在RESET=1时初始化,部分在RESET=0时初始化
这涉及到CAN模块的软件复位功能,在参考手册ATC_AC7801x_ReferenceManual_CH.pdf 的7.3.11节有说明。这里主要是设置CAN波特率的寄存器,以及CANFD选择寄存器需要在RESET=1下写入,RESET=0时就锁定了。
- void Can_Init(void)
- {
- CKGEN->CTRL |= CKGEN_CTRL_CAN0_CLK_SEL_Msk;
- CKGEN->PERI_CLK_EN_0 |= CKGEN_PERI_CLK_EN_0_CAN0_EN_Msk; ///<CAN clock en
- CKGEN->PERI_SFT_RST0 |= CKGEN_PERI_SFT_RST0_SRST_CAN0_Msk;
-
- CANx->CTRL0 |= CAN_CTRL0_RESET_Msk; ///<CAN set reset some register must write while RESET=1 and lock while RESET=0
-
- CANx->CTRL0 |= CAN_CTRL0_FDISO_Msk; ///<CANFD
- /*
- tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).
- BandRate = (48M / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1))) = 500K
- SamplePoint = (tSeg1 / (tSeg1 + tSeg2)) = 81.25%.
- */
- CANx->SBITRATE = (5 << CAN_BITRATE_PRESC_Pos) + (2 << CAN_BITRATE_SJW_Pos) + (2 << CAN_BITRATE_SEG_2_Pos) + 11; ///<Low speed
-
- ///<1M 81.25%
- CANx->FBITRATE = (2 << CAN_BITRATE_PRESC_Pos) + (2 << CAN_BITRATE_SJW_Pos) + (2 << CAN_BITRATE_SEG_2_Pos) + 11; ///<High speed
-
-
- CANx->CTRL0 &= ~CAN_CTRL0_RESET_Msk; ///<CAN reset
-
-
- CANx->CTRL1 &= ~0xFE; ///<clear all interrupt enable
-
- CANx->CTRL1 |= (CAN_CTRL1_EIE_Msk | CAN_CTRL1_RIE_Msk | CAN_CTRL1_TSIE_Msk | CAN_CTRL1_TPIE_Msk); ///<enable send receive and error interrupt
-
- CANx->CTRL1 |= (15 << CAN_CTRL1_EWL_Pos); ///<EIF limit value set 128 ((EWL+1)*8)
-
- NVIC_EnableIRQ(CAN0_IRQn);
- }
3,对于can模块,只使用STB发送,接收未设软件buff,因为STB本身已经有一个3深度的发送缓冲区,同时接收缓冲区的深度为7,加快一下芯片接收处理的速度,完全可以做到不需要软件buff,再不济可以使用硬件过滤,去除不需要接收的ID,更能减少接收的报文,避免溢出。
话说,代码好像挺多了。
Program Size: Code=2024 RO-data=240 RW-data=8 ZI-data=1264
can.rar
(371.9 KB, 下载次数: 55)
|