2020年1月21日 星期二

MCU上直譯器的應用

直譯器(Interpreter)在電腦語言上的應用已超過編譯器,但MCU工程師卻沒什麼在用。
主因在於RAM空間不足難以放入實際應用。
MCU大部分應用的RAM都是受限的。它是稀缺資源,而正統語言編譯都是用RAM很多的,二者互斥下,難有發展。
但就算是簡單直譯器,在MCU的應用中,都是很好用的方案,對於動態的事件及實務實驗有很大的幫助。
再來就是個人實務上所使用的及評估的。

終端命令直譯器
用xprintf函式很容易做。也可以轉成各式通信。再加上xmodem傳輸,可以將PC檔案直接對應到MCU內部可以管理的裝置上。
在MCU使用外部儲存上會很好用,不管是用SPI Flash或是SD卡,會很好驗證MCU的工作環境遇什麼。
有時還會看到客戶在操機器,有次從MCU讀回來的log檔中,看到客戶在做開機穩定性測試,它上電一分鐘後斷電,再一分鐘後再次上電,好在STM32有內建RTC,所以時間錄得一清二楚。問題是這種log不是一二筆,而是一整天,所以才會認為客戶在測試。

簡單語言實現
這個要用到的RAM就比較大,對於加工機器來說,常會遇到CNC指令或是其他簡單語言。大部分是用手寫程式做解析,但傳久了,往往也不符合時代(使用者會想要加自己的指令),此時就可以用到compiler-compiler,它可以吃語法解析,免去人工解析及維護的痛苦。
常用的就是flex, bison的組合,使用的RAM還可以控制。

編程於Flash?
前面都是工作做完就結束,沒有程序控制所以無需做編程。但要實現真的語言就有編程再調用,但編程後要存在那,MCU的RAM是有限的,比較沒有問題就是Flash,有無可能在執行後再加程式於flash ROM上,覺得有機會,但實在不想自造語言,光是找可以改的就找了很久。

Forth改造於Flash ROM編程
Forth語言的編程動作很像C巨集。C巨集主要是文字取代,就是找到指定的字,就進入巨集定義。若是遇到巨集定義字,就進行巨集取代。Forth有點不一樣的地方在巨集定義時以函式指標做編程,巨集取代則改成函式指標執行。
它沒有傳統的compile行為,且大部分是單次寫回,所以改成寫入flash是有機會的,因為flash ROM也可以一小筆一小筆寫回。
但要去改forth編程,將原先bit flag write以flash ROM寫回單位取代。不過有小部分功能也有問題,但是用在高階定義上,先不管,了不起變成子集語言。這樣修改後,可以成功,真的可以在未用的flash ROM上添加新的函式。但再來的問題就卡住,以致無法公開。
因為MCU界面受限,只能用串列通信來做,所以PC端一定有終端機,我在上面試用中文做為函式名,它以Big5為編碼(2 byte編碼),程式本體是函式指標這個沒有問題。但用手機終端機連上,發現它丟的是unicode(3 byte編碼),平台問題卡到,暫時先放著了。

MCU可用小型語言
RAM若是更大到1MB(STM32H7系列就有)那就可以放入一般用的小型語言。eLua是最早移入MCU的高階語言,所以lua早就鎖定很久了。但高階語言移入MCU不是沒有優勢,它可以實現從網路直接載入函式庫,就是網路函式庫可以直通MCU,這功能最早實現的就是microPython,也因為網路函式庫直通MCU,使得microPython大為流行。所以傳統MCU工程師一直看不起的直譯器,經由網路函式庫直接對應,改變的MCU直譯器的使用觀感。

2020年1月14日 星期二

STM32免費C,MCU再進化

免費,會造成經濟系統新變化。
STM32也將C變成免費,所以MCU的生態又有新變化。但這個改變不是憑空來的,個人是認為是因應RISC-V的對應行為。
其實免費的MCU C Compiler一直都在,但沒有人整合,不易上手,所以一直沒有流行起來。
這次不同了,由晶片供應商直接供應免費C,看來MCU由ARM一統再次轉成由單一晶片商一統。
C的免費,變成取用C函式庫的障礙會完全消失。再來只剩下電子問題。
在經濟學上的免費,會加速經濟發展。
簡單的模型,障礙如同河,分割二地,二地的物產交換代價大。利潤由特別管道知識的人所獲取。
第一代就是由渡船人取得,對應工程師大約是會電子又能寫組語的人,以及可以設計MCU的人。
後來造橋技術出現,可以造出直接連通的橋,就會變成很方便。
第二代由造橋人收過路費取得,對應工程師大約是會電子又會C的人,因為不用再造基礎運行單位,基本上可以設計MCU的人等於不再有任何優勢。
C的免費,等於沒有過路費,你想會如何?變成只要會C又懂電子的都會進來做生意。生意大爆發。
MCU的使用只要懂電子就行了,因為C是一般人都會的基本技能。
若是C免費是由單一廠商先行發動,又會如何?
等於各大廠商本來都是造橋人,不同的橋大家都因位置不同收不同費用,使用者要精算如何過橋才能省時省錢。現在突然有座橋不收過路費,你想會如何?

再來就要看其他做MCU的廠商如何因應了。基本上非ARM的MCU可以不用考慮了,因為組語維護困難,只能隨時代消失。

2019年9月29日 星期日

Bison使用

windows下使用
C:>win_flex  input_file.l
C:>win_bison -d input_file.y
在VS2019下會有些問題
  1. 少 unistd.h
    1. 巨集中定義 YY_NO_UNISTD_H
  2. 停用4996警告,C語言一般都有這個問題

2019年9月15日 星期日

事件驅動多工合併Coroutine

event_drive.h 
#ifndef __EVENT_DRIVE_H
#define __EVENT_DRIVE_H

#define INIT_DEVICE() resetAllTimer()
#define DIS_INTR() __asm volatile("cpsid i")
#define ENA_INTR() __asm volatile("cpsie i")

#define MAX_EVENT 4
#define MAX_TIMER 4
#define ISR_START 1
#define ISR_END (MAX_TIMER - 1)
#define SPI_TASK_ID 0

void execute(void);
void setNext(void (*p_func)(void));
unsigned int setTimeout(void (*p_func)(void), unsigned int tick);
void setTimer(unsigned int timerId, void (*p_func)(void), unsigned int tick);
void resetAllTimer(void);
void clearTimer(unsigned int id);
void ISR_setNext(void (*p_func)(void));
unsigned int ISR_setTimeout(void (*p_func)(void), unsigned int tick);
void ISR_setTimer(unsigned int timerId, void (*p_func)(void), unsigned int tick);
void timerAction(void);

#define crCREATE(p) static int crState = 0; void (* const crFunc)(void) = (p)
#define crSTART() switch (crState) { case 0:
#define crDELAY(n) do { setTimeout(crFunc, n); crState = (__LINE__); return; case (__LINE__):; } while (0)
#define crEXIT() do { crState = 0; return; } while (0)
#define crEND() }do { crState = 0; } while (0)

#endif /* __EVENT_DRIVE_H */

event_drive.c

#include "event_drive.h"

unsigned int eventInCnt = 0;
unsigned int eventOutCnt = 0;
void (*eventFunc[MAX_EVENT])(void);
void (*delayFunc[MAX_TIMER + 1])(void);
unsigned int delayCnt[MAX_TIMER + 1];

void execute(void)
{
while (eventInCnt != eventOutCnt)
{
eventFunc[eventOutCnt % MAX_EVENT]();
eventOutCnt++;
}
}

void setNext(void (*p_func)(void))
{
DIS_INTR();
eventFunc[eventInCnt % MAX_EVENT] = p_func;
eventInCnt++;
ENA_INTR();
}

unsigned int setTimeout(void (*p_func)(void), unsigned int tick)
{
register int i;

if (!tick)
tick = 1;
DIS_INTR();
i = ISR_START;
while (delayCnt[i])
{
if (i >= ISR_END)
break;
i++;
}
delayFunc[i] = p_func;
delayCnt[i] = tick;
ENA_INTR();
return i; // return timerId
}

void setTimer(unsigned int timerId, void (*p_func)(void), unsigned int tick)
{
if (!tick)
tick = 1;
if (timerId >= MAX_TIMER)
timerId = MAX_TIMER;
DIS_INTR();
delayFunc[timerId] = p_func;
delayCnt[timerId] = tick;
ENA_INTR();
}

void resetAllTimer(void)
{
int i;
for (i = 0; i < MAX_TIMER; i++)
{
delayCnt[i] = 0;
}
}

void clearTimer(unsigned int timerId)
{
if (timerId >= MAX_TIMER)
timerId = MAX_TIMER;
delayCnt[timerId] = 0;
}

void ISR_setNext(void (*p_func)(void))
{
eventFunc[eventInCnt % MAX_EVENT] = p_func;
eventInCnt++;
}

unsigned int ISR_setTimeout(void (*p_func)(void), unsigned int tick)
{
register int i;

if (!tick)
tick = 1;
i = ISR_START;
while (delayCnt[i])
{
if (i >= ISR_END)
break;
i++;
}
delayFunc[i] = p_func;
delayCnt[i] = tick;
return i;
}

void ISR_setTimer(unsigned int timerId, void (*p_func)(void), unsigned int tick)
{
if (!tick)
tick = 1;
if (timerId >= MAX_TIMER)
timerId = MAX_TIMER;
delayFunc[timerId] = p_func;
delayCnt[timerId] = tick;
}

void timerAction(void)
{
int i;
for (i = 0; i < MAX_TIMER; i++)
{
if (delayCnt[i])
{
if (!--delayCnt[i])
{
eventFunc[eventInCnt % MAX_EVENT] = delayFunc[i];
eventInCnt++;
}
}
}
}

測試程式
#include <stdio.h>
#include "event_drive.h"

void print_dot(void);
void print_0(void);
void testCoroutine(void);

void main()
{
INIT_DEVICE();
setTimeout(print_dot, 1);
setTimeout(print_0, 1);
    setTimeout(testCoroutine, 1);
    while (1)
{
execute();
}
}

void print_dot(void)
{
printf(".");
    setTimeout(print_dot, 7);
}

void print_0(void)
{
printf("'");
setTimeout(print_0, 10);
}

void testCoroutine(void)
{
    crCREATE(testCoroutine);
    crSTART();
    for (;;)
    {
        printf("1");
        crDELAY(10);
        printf("2");
        crDELAY(10);
        printf("3");
        crDELAY(100);
    }
    crEND();
}

2019年3月29日 星期五

加速規的使用

規格是用來量機器傾角。
設定讀值最大為2G,回傳值是16位元有號數。
所以值會是32767~-32768。因為有三軸,平時會量到重力。
期望重力上的軸會出現一個16384或是-16384的值。
數值上以Q值來計算,就完全不需轉成浮點。
以1G acc為單位來看,直接採用Q15格式就完全符合1G的使用。
有夾角計算,三角函式應是會用上。
實驗時只有簡單寫成單軸值檢知,一但絶對值小於0.707,就是超過45度。
所以造了一個Q16格式的cos表格,依設定角度值取cos值,加速規和表格移位到同單位Q值一比就結束。
然後是任意角度傾角計算。要先記住啟動時的三軸值。
然後又是三角函式了。這裏用的是向量內積計算,向量內積值有夾角cos的值在內。
因為已是低頻省電下的計算,計算力有限。就當成1G重力下角度計算,不用去算向量長度。
直接就是啟動時重力向量值及現在的重力向量值內積(只有乘加法計算),再移位到同單位Q值,和cos表比對,程式完成。
第一次寫程式計算力小時8051,省電下的計算可以在整數系統內完成這個任務。

2019年3月5日 星期二

PWM做DAC結果

以前的資料,放上來查

測試PWM變動後電壓上升率


測試PWM變動後電壓下降率


連續性測試


放大圖

2019年3月1日 星期五

STM32MP1 使用前分析

MCU進入多核時代,但結構不如我想的。
一般CPU多核是走同質多核。
但MCU不是,不管是NXP或是ST走的是異質多核。
MCU為何不能走同質多核?一定有問題才會走不下去。
因為異質多核對使用者不是有利的,要控制二個核心已是不易,更要做異質核操作,難上加難,若非有困難一般不會如此。
話說NXP的異質多核也出了好幾年,看來還是沒有解決同質核問題。ST也一樣。
看了一下架構圖,好像是以M4核為中心,但又不太對。
我看到的是以記憶體管理界面為中心,再掛上二組核心Dual A7及M4。
Dual A7可以管理的界面只有記憶體,ethernet,USB,SDMMC。其他的全在M4上。
也就是所有高速的資料全給Dual A7,IO全給M4。
以MCU應用來看,Dual A7才是co-processor,專門做資料處理用的處理器。
從軟體看過來,也是以M4為開機。
因為A7執行效率很高,幾乎只能在RAM中執行才能發揮。
M4及A7可以執行不同的作業系統,A7有OpenStLinux可以用。M4可有可無。
這個軟體架構和PC/BIOS的關係相同。也就是M4的工程師是BIOS工程師,A7則為PC工程師。
只是這個BIOS的腳色比PC重很多。

再來是應用領域,需要資料及IO控制。影像處理相關的可能性比較大。
和Raspberry Pi比起來,BIOS這一側的功能強化,等於在機器人應用上會更強。
或者想成Raspberry Pi+STM32原本是分開的,現在以STM32MP1合併起來。