2020年2月18日 星期二

Sine等面積計算

A=0~90
B=2/90*A
C=arccos(1-B)
D=sin(C)
C,D畫圖
A為角度
B調整分割數目

機器人座標轉換規劃

主要是幾個工作座標轉換之間的關係。
目前機器人都是吃工件檔案,機器手再輸出。中間其實沒有如此簡單。
因為機器人都是由馬達控制,所以馬達要做加減速控制。
馬達吃的指令其實是移動量/單位時間。
將馬達吃的指令也當成是指令,MCU的角色就是直譯器。
主要是將工件指令一路分解到馬達指令。
工件指令可能是DXF檔一類的,實驗或是模擬也可以用SVG來做。
目前有數個轉換在中間。
1.工件指令轉成工件座標:主要是轉成簡單向量,因為向量圖檔有一大堆高階指令,主要是分解成單一向量座標。
2.媒體座標分割:有時輸出座標過大,可能要做分次輸出,或是和檢知器對位做座標修正。
3. 分割/分檔管理:可以做輸出管理,或是重覆次數管理
4.裝置映射:機器人指尖轉換,因為機器人指尖是可以變換的。加工用的和檢查用的不會在同一個座標上。這個就要套上不同的裝置映射。例如鑽頭和camera可以在同手臂上,但看的位置不同,加工中檢查,可以快速轉換。
5.工區座標轉換:因為加工手指可能可以控制,也有被動控制,在這一階完成轉換。平移式手臂比較好轉換,轉軸式手臂就要解反向機器人運動學矩陣。另外機構座標檢查及保護也在這一層。
6.馬達路徑規劃:向量轉成馬達指令,馬達加減速路徑解析,才可以產出移動量/單位時間的指令列表。

2020年2月5日 星期三

平行編譯實驗

舊式MCU Compiler只能發動單核心執行。想利用多核心平行編譯。
找到可以利用 start指令將make分去新的cmd上去執行。這個可以成功。但合併成一個的make分不了。
另外也無法測平行化的cmd是否全部結束。
後來將編譯最久的make改成使用start /wait指令,就可以順利的接回來編譯並包成hex檔案。

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();
}