在Cortex-M3上所有的週邊皆有DMA,第一次接觸還覺得很怪。因為以往的單晶片並無此類裝置。
最奇怪的,是ADC不用DMA還不行。主因是ADC支援multi-channel,但卻只有一個data register。
若是啟動Scan功能,會一次多個channel掃入,就好像是有多個ADC,只是時間上是分開的。
但結果全部只在一個data register上。
所以問題來了,一但Scan一個channel結束,沒有取走資料,下一個channel會蓋過。
DMA的功能來了,它就是將資料依各channel分開將結果傳到RAM的位置上。
這個功能很方便,可以將RAM當成是ADC的結果register。還可以利用DMA的半滿旗標,做成double buffer。
其他週邊,如通信也有,若是已知的傳輸內容,可以設定DMA一次做完再通知。
然後就用在UART上看看,設定bund rate為1.5Mhz,就照計算上的速率在傳,傳輸利用率是100%。
Bee在一個24Mhz的單晶片上,利用DMA就實現了us級的信號時間控制。
在幾年前Bee遇到這樣的狀況會利用FPGA/CPLD去做。
但有DMA,FPGA就可以省下來了。
而且ADC也可以設定在訊號產生時做取樣,做到接近FPGA的時間控制,而且有12位元解析度。
重點是,單晶片本身的價格不高,已可以做到精確的時間上做取樣的工作。
所以單晶片在ARM Cortex-M系列的加持下,進入了新的應用方式。
接下來,只剩下工程師要如何發揮的問題了。
2012年4月14日 星期六
2012年3月23日 星期五
MCU使用變革:ADC,DAC皆免費時,數位訊號處理(DSP)將大量使用
最近使用STM32F207,發現到MCU使用習慣改變了。
因為ADC及DAC皆為內建,而且連接DMA的設定下,CPU可以去做DSP計算。
這個改變主因是有三項條件到位:
1. ADC及DAC精度提升
2. ADC取樣率提升
3. CPU運算力提升
結果使得DSP運算力到位。
DSP功能免費,可以將原先做信號處理的硬體省下來,變成軟體去做。
意指:外部的運算放大器使用率將下降。
原先的濾波器,可以使用FIR、IIR等以運算程式取代。
這對於原先就玩DSP的人也許沒有什麼。
但對於使用8051的工程師來說就不同了,因為大都沒有學過數位信號處理。
使用新的32位元微控器,將使電路大幅簡化。
而且8位元及32位元MCU差價不多,會使用DSP技術會使硬體成本下降。
"數位信號處理"技術會使得控制系統設計變得不同。
且從一開始的系統設計就呈現不一樣的思維。
也許還以為8位元MCU可以利用價格低,來取得產品優勢的這個狀況不再。
32位元MCU是較貴,但整體系統設計的元件少,會使總成本下降。
客戶買單是看總成本,而非MCU成本。
所以Cortex-M系列的低價壓制8051這件事將會成真。
單晶片工程師想要在這場MCU變革中存活下來,數位訊號處理會變成新的必備技術。
2012年2月11日 星期六
使用簡單多工3版遇到的問題
主要是在使用WakeUp()在中斷程式所遇到的問題。
因為新加的功能會方便很多,所以在中斷程式中Bee用了不少,結果還是發生程序卡死的狀況。
程式碼如下:
void ADC_Start(void)
{
void ADC_GetValue(void);
Start_ADC();
Sleep_Next(ADC_GetValue);
}
中斷程式中為
WakeUp(ADC_TASK_ID);
結果Run一段時間會卡死。
去看Task_State[ADC_TASK_ID]內容為3,就是TASK_WAIT
但ADC暫存器卻顯示已產生過中斷。
後來將Start_ADC();放在最後一行,問題就沒有了。
發生這樣的問題主要是下指令到產生中斷時間太短,在進入Sleep之前就產生中斷。
然後Sleep_Next才將TASK_WAIT寫入Task_State[ADC_TASK_ID],從此變成長睡不起。
以後要將會產生中斷的指令寫在函式最尾,以免再發生這樣的問題。
因為新加的功能會方便很多,所以在中斷程式中Bee用了不少,結果還是發生程序卡死的狀況。
程式碼如下:
void ADC_Start(void)
{
void ADC_GetValue(void);
Start_ADC();
Sleep_Next(ADC_GetValue);
}
中斷程式中為
WakeUp(ADC_TASK_ID);
結果Run一段時間會卡死。
去看Task_State[ADC_TASK_ID]內容為3,就是TASK_WAIT
但ADC暫存器卻顯示已產生過中斷。
後來將Start_ADC();放在最後一行,問題就沒有了。
發生這樣的問題主要是下指令到產生中斷時間太短,在進入Sleep之前就產生中斷。
然後Sleep_Next才將TASK_WAIT寫入Task_State[ADC_TASK_ID],從此變成長睡不起。
以後要將會產生中斷的指令寫在函式最尾,以免再發生這樣的問題。
2012年2月5日 星期日
使用Cortex-M3後的事
在前公司,一直摸不到ARM。在技術上這是一個趨勢,早晚會碰到,不如早點用,但苦無機會。
現在用Cortex-M3,不只用,還要很熟。
在設計上有次算錯了效能,結果放了一個FPGA上去。FPGA廠商很高興,因為公司以往最多用到CPLD,遇到會寫的人,自然全力支援。
就有二家全力支援產品開發,都希望有機會採用。
後來Bee就發現MCU也可以做,加上開始熟STM32,結果用中斷程式不用十行就解決了。
對公司是好的,又少了一個零件。但FPGA廠商就沒這樣高興了。
去年底出了Cortex-M4,廠商送來Demo Board,趁空擋試了一下,將FreeRTOS給裝上去,看來還不錯。
不過因為案子皆已開跑,就先放著。
然後,其他也出M4的廠商也來訪,也送來一套。過完農曆年,又一家廠商來也想推。
看來Cortex-M系列真的很拼,MCU市場還真難賺。
現在用Cortex-M3,不只用,還要很熟。
在設計上有次算錯了效能,結果放了一個FPGA上去。FPGA廠商很高興,因為公司以往最多用到CPLD,遇到會寫的人,自然全力支援。
就有二家全力支援產品開發,都希望有機會採用。
後來Bee就發現MCU也可以做,加上開始熟STM32,結果用中斷程式不用十行就解決了。
對公司是好的,又少了一個零件。但FPGA廠商就沒這樣高興了。
去年底出了Cortex-M4,廠商送來Demo Board,趁空擋試了一下,將FreeRTOS給裝上去,看來還不錯。
不過因為案子皆已開跑,就先放著。
然後,其他也出M4的廠商也來訪,也送來一套。過完農曆年,又一家廠商來也想推。
看來Cortex-M系列真的很拼,MCU市場還真難賺。
2012年1月26日 星期四
簡單多工3版
在STM32上運行時發現,可以不使用DIS_INTR()這個巨集。
因為這個在原子操作下已無需要。
後來就將Task管理,從function pointer改為原子操作下的資料。
結果發現,還可以進一步省下記憶體。
另外Skip方式也改了,改到主程式去做。現在不會跳去Dummy(),檢查完畢就移到下一個工作去。
新增功能有
WakeUp(i),可以從中斷程式中呼叫,所以可以設定只由中斷叫醒的Task,免去使用全域變數做溝通。
Sleep_Next(p_func),Task沉睡,設定醒來時執行函式,只能由WakeUp(i)叫醒。
新版本程式如下:
#include "mt.h"
#define TASK_NUM 4
extern void SimInit(void);
extern void Task1(void);
extern void Task2(void);
extern void Task3(void);
extern void OS_ENTER_CRITICAL(void);
extern void OS_EXIT_CRITICAL(void);
#define INIT_DEVICE() SimInit()
#define DIS_INTR() OS_ENTER_CRITICAL()
#define ENA_INTR() OS_EXIT_CRITICAL()
// O.S function declaim
void Dummy(void);
unsigned char FuncID;
volatile unsigned char Task_State[TASK_NUM];
unsigned short Task_Delay_Count[TASK_NUM];
void (*TaskFunc[TASK_NUM])(void);
// O.S functions
void InitSystem(void)
{
unsigned char i;
FuncID = 0;
for ( i= 0; i< TASK_NUM ; i++)
{
Task_State[i] = TASK_RUNNING;
Task_Delay_Count[i] = 0;
TaskFunc[i] = Dummy;
}
TaskFunc[1] = Task1;
TaskFunc[2] = Task2;
TaskFunc[3] = Task3;
}
void Sleep_Next(void (*p_func)(void))
{
TaskFunc[FuncID] = p_func;
Task_State[FuncID] = TASK_WAIT;
}
void WakeUp(unsigned char n)
{
Task_State[n] = TASK_RUNNING;
}
void Task_Set_Next(void (*p_func)(void))
{
TaskFunc[FuncID]=p_func;
}
void Dummy(void)
{
Sleep_Next(Dummy);
}
void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void))
{
if (! n ) n = 1;
TaskFunc[FuncID] = p_func;
Task_Delay_Count[FuncID] = n;
Task_State[FuncID] = TASK_DELAY;
}
void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void))
{
if (! n ) n = 1;
TaskFunc[FuncID] = p_func;
Task_Delay_Count[FuncID] = n;
Task_State[FuncID] = TASK_SKIP;
}
// O.S functions end
// main loop
void main(void)
{
INIT_DEVICE();
InitSystem();
while (1)
{
switch (Task_State[FuncID])
{
case TASK_RUNNING :
TaskFunc[FuncID]();
break;
case TASK_SKIP :
if ( Task_Delay_Count[FuncID] )
{
Task_Delay_Count[FuncID]--;
if (! Task_Delay_Count[FuncID]) WakeUp(FuncID);
}
break;
default:
break;
}
if ( ++FuncID >= TASK_NUM ) FuncID = 0;
}
}
void TimeTick(void) // This is timer interrupt
{
unsigned char i;
for ( i=0; i< TASK_NUM; i++)
{
if ( Task_State[i] == TASK_DELAY )
{
if ( Task_Delay_Count[i] )
{
Task_Delay_Count[i]--;
if (! Task_Delay_Count[i]) WakeUp(i);
}
}
}
}
// Begin User Tasks
mt.h內容為
void Sleep_Next(void (*p_func)(void));
void WakeUp(unsigned char n);
void Task_Set_Next(void (*p_func)(void));
void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void));
void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void));
// Task State
#define TASK_RUNNING 0
#define TASK_SKIP 1
#define TASK_DELAY 2
#define TASK_WAIT 3
實驗程式如下:
#include < stdio.h >
#include "mt.h"
void Task1(void)
{
printf("G");
Task_Delay_Ms_Next(10,Task1);
}
void Task2(void)
{
printf("z");
Task_Delay_Ms_Next(1,Task2);
}
void Task3(void)
{
printf(".");
Task_Set_Skip_Next(60000,Task3);
}
Windows模擬結果
因為這個在原子操作下已無需要。
後來就將Task管理,從function pointer改為原子操作下的資料。
結果發現,還可以進一步省下記憶體。
另外Skip方式也改了,改到主程式去做。現在不會跳去Dummy(),檢查完畢就移到下一個工作去。
新增功能有
WakeUp(i),可以從中斷程式中呼叫,所以可以設定只由中斷叫醒的Task,免去使用全域變數做溝通。
Sleep_Next(p_func),Task沉睡,設定醒來時執行函式,只能由WakeUp(i)叫醒。
新版本程式如下:
#include "mt.h"
#define TASK_NUM 4
extern void SimInit(void);
extern void Task1(void);
extern void Task2(void);
extern void Task3(void);
extern void OS_ENTER_CRITICAL(void);
extern void OS_EXIT_CRITICAL(void);
#define INIT_DEVICE() SimInit()
#define DIS_INTR() OS_ENTER_CRITICAL()
#define ENA_INTR() OS_EXIT_CRITICAL()
// O.S function declaim
void Dummy(void);
unsigned char FuncID;
volatile unsigned char Task_State[TASK_NUM];
unsigned short Task_Delay_Count[TASK_NUM];
void (*TaskFunc[TASK_NUM])(void);
// O.S functions
void InitSystem(void)
{
unsigned char i;
FuncID = 0;
for ( i= 0; i< TASK_NUM ; i++)
{
Task_State[i] = TASK_RUNNING;
Task_Delay_Count[i] = 0;
TaskFunc[i] = Dummy;
}
TaskFunc[1] = Task1;
TaskFunc[2] = Task2;
TaskFunc[3] = Task3;
}
void Sleep_Next(void (*p_func)(void))
{
TaskFunc[FuncID] = p_func;
Task_State[FuncID] = TASK_WAIT;
}
void WakeUp(unsigned char n)
{
Task_State[n] = TASK_RUNNING;
}
void Task_Set_Next(void (*p_func)(void))
{
TaskFunc[FuncID]=p_func;
}
void Dummy(void)
{
Sleep_Next(Dummy);
}
void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void))
{
if (! n ) n = 1;
TaskFunc[FuncID] = p_func;
Task_Delay_Count[FuncID] = n;
Task_State[FuncID] = TASK_DELAY;
}
void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void))
{
if (! n ) n = 1;
TaskFunc[FuncID] = p_func;
Task_Delay_Count[FuncID] = n;
Task_State[FuncID] = TASK_SKIP;
}
// O.S functions end
// main loop
void main(void)
{
INIT_DEVICE();
InitSystem();
while (1)
{
switch (Task_State[FuncID])
{
case TASK_RUNNING :
TaskFunc[FuncID]();
break;
case TASK_SKIP :
if ( Task_Delay_Count[FuncID] )
{
Task_Delay_Count[FuncID]--;
if (! Task_Delay_Count[FuncID]) WakeUp(FuncID);
}
break;
default:
break;
}
if ( ++FuncID >= TASK_NUM ) FuncID = 0;
}
}
void TimeTick(void) // This is timer interrupt
{
unsigned char i;
for ( i=0; i< TASK_NUM; i++)
{
if ( Task_State[i] == TASK_DELAY )
{
if ( Task_Delay_Count[i] )
{
Task_Delay_Count[i]--;
if (! Task_Delay_Count[i]) WakeUp(i);
}
}
}
}
// Begin User Tasks
mt.h內容為
void Sleep_Next(void (*p_func)(void));
void WakeUp(unsigned char n);
void Task_Set_Next(void (*p_func)(void));
void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void));
void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void));
// Task State
#define TASK_RUNNING 0
#define TASK_SKIP 1
#define TASK_DELAY 2
#define TASK_WAIT 3
實驗程式如下:
#include < stdio.h >
#include "mt.h"
void Task1(void)
{
printf("G");
Task_Delay_Ms_Next(10,Task1);
}
void Task2(void)
{
printf("z");
Task_Delay_Ms_Next(1,Task2);
}
void Task3(void)
{
printf(".");
Task_Set_Skip_Next(60000,Task3);
}
Windows模擬結果
2011年9月4日 星期日
簡單多工2版
用在PIC18、PIC33時發現一些問題,做了修改,同時加入windows平台下的模擬程式。
主程式:
#define TASK_NUM 4
extern void SimInit(void);
extern void Task1(void);
extern void Task2(void);
extern void OS_ENTER_CRITICAL(void);
extern void OS_EXIT_CRITICAL(void);
#define INIT_DEVICE() SimInit()
#define DIS_INTR() OS_ENTER_CRITICAL()
#define ENA_INTR() OS_EXIT_CRITICAL()
// O.S function declaim
void Dummy(void);
unsigned char FuncID;
unsigned int Task_Delay_Count[TASK_NUM];
unsigned int Task_Skip_Count[TASK_NUM];
void (*TaskFunc[TASK_NUM])(void);
void (*TaskResumeFunc[TASK_NUM])(void);
// O.S functions
void InitSystem(void)
{
unsigned char i;
FuncID = 0;
for ( i= 0; i< TASK_NUM ; i++)
{
Task_Delay_Count[i] = Task_Skip_Count[i] = 0;
TaskFunc[i] = TaskResumeFunc[i] = Dummy;
}
TaskFunc[1] = Task1;
TaskFunc[2] = Task2;
}
void Dummy(void)
{
return;
}
void Task_Set_Next(void (*p_func)(void))
{
TaskFunc[FuncID]=p_func;
}
void Task_Set_Other_Task(unsigned char id, void (*p_func)(void))
{
DIS_INTR();
TaskFunc[id]=p_func;
ENA_INTR();
}
void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void))
{
if (! n ) n = 1;
TaskResumeFunc[FuncID]=p_func;
TaskFunc[FuncID] = Dummy; // to sleep
DIS_INTR();
Task_Delay_Count[FuncID] = n;
ENA_INTR();
}
static void Dummy_Skip(void)
{
if ( Task_Skip_Count[FuncID] )
{
Task_Skip_Count[FuncID]--;
if (! Task_Skip_Count[FuncID]) TaskFunc[FuncID]=TaskResumeFunc[FuncID];
}
}
void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void))
{
if (! n ) n = 1;
TaskResumeFunc[FuncID]=p_func;
TaskFunc[FuncID] = Dummy_Skip; // to sleep
Task_Skip_Count[FuncID] = n;
}
// O.S functions end
// main loop
void main(void)
{
INIT_DEVICE();
InitSystem();
while (1)
{
register void (*Current_Func)(void);
DIS_INTR();
Current_Func = TaskFunc[FuncID]; // may break with interrupt
ENA_INTR();
// Trace System Code maybe add here
Current_Func();
if( ++FuncID >= TASK_NUM ) FuncID = 0;
}
}
void TimeTick(void) // This is timer interrupt
{
unsigned char i;
for ( i=0; i< TASK_NUM; i++)
{
if ( Task_Delay_Count[i] )
{
Task_Delay_Count[i]--;
if (! Task_Delay_Count[i]) TaskFunc[i]=TaskResumeFunc[i]; // wake up function
}
}
}
給其他C檔案用的引入檔mt.h
extern void Task_Set_Next(void (*p_func)(void));
extern void Task_Set_Other_Task(unsigned char id, void (*p_func)(void));
extern void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void));
extern void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void));
Windows下模擬用程式
#include <windows.h>
#include <winbase.h>
extern void TimeTick(void);
HANDLE OSSemaphore;
DWORD WINAPI OSTickW32 ( LPVOID lpParameter );
HANDLE OSTick32Handle;
void SimInit(void)
{
DWORD dwID;
OSSemaphore = CreateSemaphore( NULL, 1, 1, NULL );
OSTick32Handle = CreateThread( NULL, 0, OSTickW32, 0, 0, &dwID );
SetPriorityClass(OSTick32Handle,THREAD_PRIORITY_HIGHEST);
SetThreadPriority(OSTick32Handle,THREAD_PRIORITY_HIGHEST);
}
DWORD WINAPI OSTickW32( LPVOID lpParameter )
{
while(1)
{
TimeTick();
Sleep(1);
}
return 0;
}
void OS_SLEEP(unsigned int count)
{
Sleep(count);
}
void OS_INIT_CRITICAL(void)
{
return;
}
void OS_ENTER_CRITICAL(void)
{
WaitForSingleObject( OSSemaphore, INFINITE );
}
void OS_EXIT_CRITICAL(void)
{
ReleaseSemaphore( OSSemaphore, 1, NULL );
}
測試用程式
#include <stdio.h>
#include "mt.h"
void Task1(void)
{
printf("G");
Task_Delay_Ms_Next(100,Task1);
}
void Task2(void)
{
printf("z");
Task_Delay_Ms_Next(33,Task2);
}
測試畫面
要記得請使用多核心下去跑,因為本來就不是給Windows用的,所以會用掉一個核心。
主程式:
#define TASK_NUM 4
extern void SimInit(void);
extern void Task1(void);
extern void Task2(void);
extern void OS_ENTER_CRITICAL(void);
extern void OS_EXIT_CRITICAL(void);
#define INIT_DEVICE() SimInit()
#define DIS_INTR() OS_ENTER_CRITICAL()
#define ENA_INTR() OS_EXIT_CRITICAL()
// O.S function declaim
void Dummy(void);
unsigned char FuncID;
unsigned int Task_Delay_Count[TASK_NUM];
unsigned int Task_Skip_Count[TASK_NUM];
void (*TaskFunc[TASK_NUM])(void);
void (*TaskResumeFunc[TASK_NUM])(void);
// O.S functions
void InitSystem(void)
{
unsigned char i;
FuncID = 0;
for ( i= 0; i< TASK_NUM ; i++)
{
Task_Delay_Count[i] = Task_Skip_Count[i] = 0;
TaskFunc[i] = TaskResumeFunc[i] = Dummy;
}
TaskFunc[1] = Task1;
TaskFunc[2] = Task2;
}
void Dummy(void)
{
return;
}
void Task_Set_Next(void (*p_func)(void))
{
TaskFunc[FuncID]=p_func;
}
void Task_Set_Other_Task(unsigned char id, void (*p_func)(void))
{
DIS_INTR();
TaskFunc[id]=p_func;
ENA_INTR();
}
void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void))
{
if (! n ) n = 1;
TaskResumeFunc[FuncID]=p_func;
TaskFunc[FuncID] = Dummy; // to sleep
DIS_INTR();
Task_Delay_Count[FuncID] = n;
ENA_INTR();
}
static void Dummy_Skip(void)
{
if ( Task_Skip_Count[FuncID] )
{
Task_Skip_Count[FuncID]--;
if (! Task_Skip_Count[FuncID]) TaskFunc[FuncID]=TaskResumeFunc[FuncID];
}
}
void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void))
{
if (! n ) n = 1;
TaskResumeFunc[FuncID]=p_func;
TaskFunc[FuncID] = Dummy_Skip; // to sleep
Task_Skip_Count[FuncID] = n;
}
// O.S functions end
// main loop
void main(void)
{
INIT_DEVICE();
InitSystem();
while (1)
{
register void (*Current_Func)(void);
DIS_INTR();
Current_Func = TaskFunc[FuncID]; // may break with interrupt
ENA_INTR();
// Trace System Code maybe add here
Current_Func();
if( ++FuncID >= TASK_NUM ) FuncID = 0;
}
}
void TimeTick(void) // This is timer interrupt
{
unsigned char i;
for ( i=0; i< TASK_NUM; i++)
{
if ( Task_Delay_Count[i] )
{
Task_Delay_Count[i]--;
if (! Task_Delay_Count[i]) TaskFunc[i]=TaskResumeFunc[i]; // wake up function
}
}
}
給其他C檔案用的引入檔mt.h
extern void Task_Set_Next(void (*p_func)(void));
extern void Task_Set_Other_Task(unsigned char id, void (*p_func)(void));
extern void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void));
extern void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void));
Windows下模擬用程式
#include <windows.h>
#include <winbase.h>
extern void TimeTick(void);
HANDLE OSSemaphore;
DWORD WINAPI OSTickW32 ( LPVOID lpParameter );
HANDLE OSTick32Handle;
void SimInit(void)
{
DWORD dwID;
OSSemaphore = CreateSemaphore( NULL, 1, 1, NULL );
OSTick32Handle = CreateThread( NULL, 0, OSTickW32, 0, 0, &dwID );
SetPriorityClass(OSTick32Handle,THREAD_PRIORITY_HIGHEST);
SetThreadPriority(OSTick32Handle,THREAD_PRIORITY_HIGHEST);
}
DWORD WINAPI OSTickW32( LPVOID lpParameter )
{
while(1)
{
TimeTick();
Sleep(1);
}
return 0;
}
void OS_SLEEP(unsigned int count)
{
Sleep(count);
}
void OS_INIT_CRITICAL(void)
{
return;
}
void OS_ENTER_CRITICAL(void)
{
WaitForSingleObject( OSSemaphore, INFINITE );
}
void OS_EXIT_CRITICAL(void)
{
ReleaseSemaphore( OSSemaphore, 1, NULL );
}
測試用程式
#include <stdio.h>
#include "mt.h"
void Task1(void)
{
printf("G");
Task_Delay_Ms_Next(100,Task1);
}
void Task2(void)
{
printf("z");
Task_Delay_Ms_Next(33,Task2);
}
測試畫面
要記得請使用多核心下去跑,因為本來就不是給Windows用的,所以會用掉一個核心。
2011年8月20日 星期六
Flash Forth的運行原理
因為使用到PIC,於是看看有無Forth可用,於是找到Flash Forth。
另一個目標是找Cortex M3上的Forth,結果找到一個分散式的Forth,PC端是用TCL寫的,TCL很不熟,就先放著。
比較令我感興趣的是PIC18上的Flash Forth。
雖然丁陳老師的eForth有做在PIC17上。但無法做新加程式,因為無法將程式寫回Flash。
但Flash Forth在PIC18上可以將程式寫回Flash。
因為MCU上我比較少做這個動作,所以沒有想到其實可以寫回Flash,就可以Run完整的Forth。
看了一下,就把回寫的地方改為燒回Flash的函式。
雖然寫回Flash是很慢,但人的反應也不快,所以不會感覺到。
只要Run的夠快就好了。
有去比對其他Forth,MSP430上的CamelForth也有這樣的能力。
不過作者有發現一個問題,就是CREATE> 指令受到影響。
而改以另一個指令去取代。
還是比較希望有Flash Forth在Cortex M3上面。目前還沒有看到。
Bee是知道FIG Taiwan的Holi有ARM7 Forth。不過他的堆疊成長方向和Cortex M3相反,要移反而麻煩。
只能說是Holi選錯了方向,因為ARM7確實二個方向都可以。
不過Cortex M3因為要精簡,就變成單向。而且組合語言指令有16 bit及32 bit混合,不像ARM7固定在32 bit上。
這些改變都要去動Forth核心動作。重寫可能還比改寫快。
另一個目標是找Cortex M3上的Forth,結果找到一個分散式的Forth,PC端是用TCL寫的,TCL很不熟,就先放著。
比較令我感興趣的是PIC18上的Flash Forth。
雖然丁陳老師的eForth有做在PIC17上。但無法做新加程式,因為無法將程式寫回Flash。
但Flash Forth在PIC18上可以將程式寫回Flash。
因為MCU上我比較少做這個動作,所以沒有想到其實可以寫回Flash,就可以Run完整的Forth。
看了一下,就把回寫的地方改為燒回Flash的函式。
雖然寫回Flash是很慢,但人的反應也不快,所以不會感覺到。
只要Run的夠快就好了。
有去比對其他Forth,MSP430上的CamelForth也有這樣的能力。
不過作者有發現一個問題,就是CREATE> 指令受到影響。
而改以另一個指令去取代。
還是比較希望有Flash Forth在Cortex M3上面。目前還沒有看到。
Bee是知道FIG Taiwan的Holi有ARM7 Forth。不過他的堆疊成長方向和Cortex M3相反,要移反而麻煩。
只能說是Holi選錯了方向,因為ARM7確實二個方向都可以。
不過Cortex M3因為要精簡,就變成單向。而且組合語言指令有16 bit及32 bit混合,不像ARM7固定在32 bit上。
這些改變都要去動Forth核心動作。重寫可能還比改寫快。
訂閱:
文章 (Atom)

