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合併起來。

2019年2月27日 星期三

利用Vrefint校正ADC

電池相關裝置,因為省電,一般不會安裝穩壓元件,Pin數少的MCU也無外部Vref可用。
可以利用STM32內建的ADC_IN17生成的固定電壓源做數值校正。
aADCxConvertedData[4]就是ADC_IN17,預設值為1510,若是現值變了,轉換值就存於v_factor。故ADC取值成功,就先做轉換值計算,其他的ADC值就可以依轉換值回推到原值。

int v_factor;
unsigned short adc_value[ADC_CONVETED_DATA_BUFFER_SIZE - 1];
#define V_STD (1510)
#define V_FACTOR_SET(n) (v_factor = ((V_STD << 16) / (n)))
#define V_FACTOR_ADJ(x) (((x)*v_factor) >> 16)
HAL_ADCEx_EnableVREFINT();
MX_ADC_Init();
HAL_ADC_Start_DMA(&hadc, (uint32_t *)aADCxConvertedData, ADC_CONVERTED_DATA_BUFFER_SIZE);
crDELAY(xHandle, MS(2));
V_FACTOR_SET(aADCxConvertedData[4]);
adc_value[0] = V_FACTOR_ADJ(aADCxConvertedData[0]);
adc_value[1] = V_FACTOR_ADJ(aADCxConvertedData[1]);
adc_value[2] = V_FACTOR_ADJ(aADCxConvertedData[2]);
adc_value[3] = V_FACTOR_ADJ(aADCxConvertedData[3]);


2019年1月29日 星期二

量子時代

手機是現科技及經濟指標產品。它的下一代也是科技方向。所以再下去就是量子時代。
鏡頭用量子光學薄膜,取代光學透鏡。
螢幕色彩用量子點,可以自由控制發光波長。
環境檢知(AR用)雷射,用量子光陷阱共振腔。
通信用量子加密。
服務用計算機是量子電腦。手機上會不會引入量子電腦看來只是時間上的問題。
觸控用的石墨烯運作原理也和量子有關。
記憶體不知何時會有量子記憶體。
只剩下電池還沒有看到量子插手,但不保證。



看來已不是只有量子霸權問題,根本是進入量子時代。

2019年1月28日 星期一

FreeRTOS標準化最後一哩路:POSIX

MCU一直無法標準化的一項原因在於RAM/ROM太小且計算力不足。
所以RTOS才會推展速度不快。
MCU受限最大的資源是RAM。而PC資源上RAM往往是不缺的,不管做什麼事都在RAM上。
MCU卻是RAM的限制,RTOS無法有效用,解譯器也不太能用,其他標準化都不易。
但QSPI XIP解除限制,使得MCU上的RAM增加到可以用的量。可以說快要進入RAM應用的爆發點。

RAM足用的狀況下,第一個使用的管理軟體就是RTOS。
然後只差人工修整PC函式庫去符合MCU的使用環境。

這回Amazon助推了一把,實現的FreeRTOS POSIX界面。這樣人工修整的地方又可以少了很多。
MCU上的RTOS具有POSIX的不是新鮮事。這是廢話,只是發表性文章還是要再重提一次。要錢的RTOS都有提供。
但免費是一種力量。所以免費RTOS上有提供POSIX會直接將MCU推入高生產力程式設計。
再加上一堆Code Generator負責解決底層驅動問題。MCU程式生產力開始變成一種工程性設計,跳開以前的藝術性設計。

工程性設計:模組化,工具化,拼裝。都是為了可以快速生產而產生的。但要會用,自然要會它的SOP。不像藝術性程式設計,是個人化舞台。工程性設計是可以打群戰,更可以做到不同裝置不同人寫及驗證。然後組合後還可以正常運行。
MCU一直是單兵作戰的市場,但現在情況有變。RTOS及POSIX未來將變成高生產力的標準工具。心有餘力的工程師還是早早做準備。我知道很多人才從組合語言的坑中爬出來重新適應C,但再下來是RTOS及軟體工程這個大坑。