【ch32v307】TIM1替代FreeRtos的Systick 發(fā)生問(wèn)題

ch32v307中64位的Systick可以不回繞地一直計(jì)數(shù),是系統(tǒng)很好的一個(gè)絕對(duì)時(shí)標(biāo),不必用中斷而能提供阻塞式的和非阻塞式的延時(shí)。公版的Systick延時(shí)示例不是一個(gè)理想的應(yīng)用方式,它會(huì)復(fù)位計(jì)數(shù)器,只適合單線程的應(yīng)用,我們可以讓它一直計(jì)時(shí)而不重載,要讓它計(jì)滿得幾千年。

為了不浪費(fèi)Systick,想用TIM1替代FreeRtos示例里的Systick,不過(guò)事情很奇怪,重新上電后的第一次運(yùn)行總是出錯(cuò),進(jìn)行一次手工Reset復(fù)位后卻能正常運(yùn)行,而使用Systick不會(huì)發(fā)生。port.c中的代碼如下:


#define CFGR0_PPRE2_Set_Mask? ? ? ?((uint32_t)0x00003800)


/* just for wch's systick,don't have mtime */

void vPortSetupTimerInterrupt( void )

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};

NVIC_InitTypeDef NVIC_InitStructure = {0};


? ? /* set software is lowest priority */

? ? NVIC_SetPriority(Software_IRQn,0xf0);

? ? NVIC_EnableIRQ(Software_IRQn);


? ? RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);


? ? RCC_ClocksTypeDef RCC_ClocksStatus;

? ? RCC_GetClocksFreq(&RCC_ClocksStatus);


? ? uint32_t tmp = RCC->CFGR0 & CFGR0_PPRE2_Set_Mask;

? ? tmp = tmp >> 11;

? ? if(tmp != 0) RCC_ClocksStatus.PCLK2_Frequency *= 2;


? ? TIM_InternalClockConfig(TIM1);


? ? TIM_TimeBaseStructure.TIM_Prescaler = RCC_ClocksStatus.PCLK2_Frequency / 1000000 - 1;? ?//指定用于劃分TIM時(shí)鐘的預(yù)分頻值,使其轉(zhuǎn)化為微秒

? ? TIM_TimeBaseStructure.TIM_Period = 1000000 / configTICK_RATE_HZ - 1;? ? ? //指定下次更新事件時(shí)要加載到活動(dòng)自動(dòng)重新加載寄存器中的周期值

? ? TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;? ? ? ? ?//時(shí)鐘分頻因子

? ? TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;? ? ?//TIM計(jì)數(shù)模式,向上計(jì)數(shù)模式

? ? TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);? ? ? ? ? ? ? ? ?//根據(jù)指定的參數(shù)初始化TIMx的時(shí)間基數(shù)單位


? ? TIM_Cmd(TIM1, ENABLE);


? ? /* set TIM1 is lowest priority */

//? ? NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;? ? ? ? ? ? ?//TIM1中斷

//? ? NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;? ? ? ?//設(shè)置搶占優(yōu)先級(jí)1

//? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority = 15;? ? ? ? ? ? ? //設(shè)置響應(yīng)優(yōu)先級(jí)7

//? ? NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;? ? ? ? ? ? ? ? ?//使能通道1中斷

//? ? NVIC_Init(&NVIC_InitStructure);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//初始化NVIC


? ? /* set systick is lowest priority */

? ? NVIC_SetPriority(TIM1_UP_IRQn,0xf0);

? ? NVIC_EnableIRQ(TIM1_UP_IRQn);


? ? TIM_ITConfig( TIM1, TIM_IT_Update, ENABLE );

}


/*-----------------------------------------------------------*/

void TIM1_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

void TIM1_UP_IRQHandler( void )

{

? ? /* TIM Update event */

? ? if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)

? ? {

? ? ? ? GET_INT_SP();

? ? ? ? portDISABLE_INTERRUPTS();

? ? ? ? if( xTaskIncrementTick() != pdFALSE )

? ? ? ? {

? ? ? ? ? ? portYIELD();

? ? ? ? }

? ? ? ? portENABLE_INTERRUPTS();

? ? ? ? FREE_INT_SP();


? ? ? ? TIM_ClearITPendingBit( TIM1, TIM_IT_Update );

? ? }

}


TIM1的中斷正常觸發(fā)后,在執(zhí)行到TIM1_UP_IRQHandler中的xTaskIncrementTick( )后,跟蹤到task.c:


? ? ? ? const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;


執(zhí)行后直接觸發(fā)HardFault_Handler 中斷,發(fā)生錯(cuò)誤,這問(wèn)題在哪里呢?

臨時(shí)的解決辦法:

uint64_t?CmpValueAdd;
/*?just?for?wch's?systick,don't?have?mtime?*/
void?vPortSetupTimerInterrupt(?void?)
{
????/*?set?software?is?lowest?priority?*/
????NVIC_SetPriority(Software_IRQn,0xf0);
????NVIC_EnableIRQ(Software_IRQn);
????/*?set?systick?is?lowest?priority?*/
????NVIC_SetPriority(SysTicK_IRQn,0xf0);
????NVIC_EnableIRQ(SysTicK_IRQn);
????SysTick->CTLR=?0;
????SysTick->SR??=?0;
????SysTick->CNT?=?0;
????/*??*********?*/
????CmpValueAdd?=?configCPU_CLOCK_HZ/configTICK_RATE_HZ/8;????
????SysTick->CMP?=?CmpValueAdd;
????SysTick->CTLR=?0x3;
????/*??*********?*/
}
/*-----------------------------------------------------------*/
void?SysTick_Handler(void)?__attribute__((interrupt("WCH-Interrupt-fast")));
void?SysTick_Handler(?void?)
{
????GET_INT_SP();
????portDISABLE_INTERRUPTS();
????SysTick->SR=0;
????/*??*********?*/
????SysTick->CMP?=?SysTick->CNT?+?CmpValueAdd;
????/*??*********?*/
????if(?xTaskIncrementTick()?!=?pdFALSE?)
????{
????????portYIELD();
????}
????portENABLE_INTERRUPTS();
????FREE_INT_SP();
}



我們讓Systick不回零,始終向上計(jì)數(shù),在Debug.c中

int?pule_us?=?0;
int?pule_ms?=?0;
/****************************************
??????獲得系統(tǒng)當(dāng)前以1毫秒為單位的滴答計(jì)數(shù)
??????類(lèi)似于?STM32的函數(shù)
/****************************************
uint64_t?HAL_GetTick()
{
????return?SysTick->CNT?/?pule_ms?;
}
/***************************************
??????????????????初始化
***************************************/
void?Delay_Init(void)
{
????pule_us?=?SystemCoreClock?/?8000000;
????pule_ms?=?(uint16_t)pule_us?*?1000;
????SysTick->CTLR?=?(1?<<?5)?|?1;??//?計(jì)數(shù)器初始值更新=0,?啟動(dòng)計(jì)數(shù)器。?關(guān)中斷、1/8時(shí)基、到比較值后繼續(xù)、向上計(jì)數(shù)
}
/***************************************
???????????????阻塞式的微秒延時(shí)
***************************************/
void?Delay_Us(uint32_t?n)
{
uint64_t?Cmp?=?SysTick->CNT?+?(uint32_t)n?*?pule_us;
????while(SysTick->CNT?<?Cmp);
}
/***************************************
???????????????阻塞式的毫秒延時(shí)
***************************************/
void?Delay_Ms(uint32_t?n)
{
uint64_t?Cmp?=?SysTick->CNT?+?(uint32_t)n?*?pule_ms;
????while(SysTick->CNT?<?Cmp);
}



您好,你可以將中斷函數(shù)聲明按照下圖方式修改一下試試,當(dāng)運(yùn)行RTOS時(shí),中斷函數(shù)聲明建議采用__attribute__((interrupt))聲明。

image.png


按您說(shuō)的進(jìn)行了修改,問(wèn)題沒(méi)有解決。

icon_rar.gifEXAM.rar

使用的沁恒的v307開(kāi)發(fā)板,下載后,USB重新連接上電死機(jī),按下Reset鍵后正常。


您好,請(qǐng)問(wèn)你運(yùn)行的是哪個(gè)工程?FreeRTOS那個(gè)么,我下載后上電正常運(yùn)行,兩個(gè)任務(wù)都在工作,LED正常閃爍,并沒(méi)有出現(xiàn)死機(jī)現(xiàn)象,若方便,可以具體描述一下異常的現(xiàn)象和正常運(yùn)行時(shí)的現(xiàn)象,也可通過(guò)郵箱和我溝通(lzs@wch.cn)


是AppTest。? Hex文件可能較老(另外它的起始地址在8000,有可能刷了后運(yùn)行的并不是它),需要重新編譯(設(shè)置里是生成bin),.ld文件已經(jīng)把地址改為 0x00000000。

還有,寫(xiě)了bootloader 文件,通過(guò)CAN總線刷寫(xiě)APP到FLASH,有時(shí)候連續(xù)成功,有時(shí)候連續(xù)不成功。表現(xiàn)是刷寫(xiě)20k的bin到85%左右發(fā)現(xiàn)校驗(yàn)錯(cuò)誤,即寫(xiě)入的內(nèi)容與讀出的內(nèi)容不一致。寫(xiě)入過(guò)程很簡(jiǎn)單:收到4字節(jié)以WORD方式寫(xiě)入,成功后向主機(jī)繼續(xù)請(qǐng)求下一個(gè)WORD,收到后再次寫(xiě)入。

/*?Program?32bit?data?into?flash?---------------------------------------------*/
bool?Flash_Write32(uint32_t?data)
{
????if((flash_ptr?>?(FLASH_END_ADDRESS?-?3))?||?(flash_ptr?<?FLASH_STARTADDRESS)?)
????{
????????FLASH_Lock();
????????return?false;
????}
????if(FLASH_ProgramWord(flash_ptr,(uint64_t)?data)?==?FLASH_COMPLETE)
????{
????????/*?Check?the?written?value?*/
????????if(*(__IO?uint32_t*)flash_ptr?!=?data)
????????{
????????????/*?Flash?content?doesn't?match?source?content?*/
????????????printf("Write?Error?at:?%p\r\nWRITE:?%x\r\nFLASH:?%x\r\n",?flash_ptr,?data,?*(__IO?uint32_t*)flash_ptr);
????????????FLASH_Lock();
????????????return?false;
????????}
????????/*?Increment?Flash?destination?address?*/
????????flash_ptr?+=?4;
????}
????else
????{
????????/*?Error?occurred?while?writing?data?into?Flash?*/
????????printf("Write?Error\r\n",?*(uint32_t*)flash_ptr,?data);
????????FLASH_Lock();
????????return?false;
????}
????return?true;
}

發(fā)生錯(cuò)誤時(shí)4個(gè)字節(jié)中有一個(gè)字節(jié)某些位不對(duì),有時(shí)候是多0,有時(shí)候是多1

2022-05-27_171519.png



我為了構(gòu)建84MHz的時(shí)鐘(以前STM項(xiàng)目繼承的,搞了一個(gè)奇怪的CAN波特率,要有3和7的倍數(shù)),只好使用了兩級(jí)PLL。但是代碼庫(kù)中的RCC_GetClocksFreq()編寫(xiě)的太原始,未考慮PLL2的作用,導(dǎo)致串口時(shí)鐘不對(duì),打印輸出亂碼。我已經(jīng)進(jìn)行了修改,將獲取SYSCLK的過(guò)程單獨(dú)拿出來(lái)作為一個(gè)弱函數(shù)。期待官方后期繼續(xù)完善。


您好,這邊對(duì)AppTest例程進(jìn)行下載測(cè)試,并在下載之前刪除了原有的bin文件和hex文件,重新生成bin文件下載,下載之后看不到任何現(xiàn)象,串口也沒(méi)有打印,包括重新上電復(fù)位之后,為了問(wèn)題快速解決,建議你那邊測(cè)試一下發(fā)一個(gè)可復(fù)現(xiàn)問(wèn)題的例程過(guò)來(lái)


Flash寫(xiě)錯(cuò)誤的問(wèn)題找到了,是我少擦除了一部分。在此提醒廠家,希望例子代碼更嚴(yán)謹(jǐn)些。

問(wèn)題的發(fā)生就在于例子中擦除塊的計(jì)算:

? ? NbrOfPage = (PAGE_WRITE_END_ADDR - PAGE_WRITE_START_ADDR) / FLASH_PAGE_SIZE;

很顯然,總擦除字節(jié)數(shù)不是FLASH_PAGE_SIZE整倍數(shù)的時(shí)候,一定少擦除了。另外當(dāng)PAGE_WRITE_START_ADDR并非以FLASH_PAGE_SIZE對(duì)齊的時(shí)候也一定不正確。

我們開(kāi)發(fā)人員由于對(duì)芯片運(yùn)行機(jī)制了解的不一定全面,經(jīng)常會(huì)將廠方例子代碼奉為經(jīng)典,經(jīng)常不敢輕易改動(dòng)。而廠方測(cè)試代碼編寫(xiě)人員經(jīng)常以測(cè)試為目的,考慮的不夠全面,默認(rèn)用戶會(huì)仔細(xì)閱讀并修改代碼,所以希望廠方提高思想認(rèn)識(shí),以用戶角度思考問(wèn)題,多替用戶著想,簡(jiǎn)化處理的部分也要寫(xiě)出詳細(xì)注釋?zhuān)f(shuō)明需要修改的地方和方法。

不要嫌我多嘴,我是支持國(guó)產(chǎn)替代才提意見(jiàn),如果不想用,干嘛多費(fèi)唾沫。


您好,感謝你的反饋和建議,這邊會(huì)和相關(guān)工程師反饋的。


只有登錄才能回復(fù),可以選擇微信賬號(hào)登錄

国产91精品新入口,国产成人综合网在线播放,九热这里只有精品,本道在线观看,美女视频a美女视频,韩国美女激情视频,日本美女pvp视频