2017年5月24日 星期三

VS Code使用IAR設定

VS Code C/C++插件升級後,變成無法去找出原先定義的地方。
後來發現是VS Code沒有IAR設定生成的問題,就試著手工填看看,結果有成功。
開入STM32專案目錄後,開C檔會有一堆紅標。
點任一個紅標字,左側會出現一個小燈泡,去點它,會開啟c_cpp_properties.json檔
先借用win32的除錯器來用。
原文:
"name": "Win32",
"includePath": [
"${workspaceRoot}",
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10586.0/um",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10586.0/ucrt",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10586.0/shared",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10586.0/winrt"
],
"defines": [
"_DEBUG",
"UNICODE"
],
改成:
"name": "Win32",
"includePath": [
"${workspaceRoot}/",
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10586.0/um",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10586.0/ucrt",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10586.0/shared",
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.10586.0/winrt",
"${workspaceRoot}/BLE_CNTR/Inc",
"${workspaceRoot}/BLE_CNTR/Drivers/STM32L0xx_HAL_Driver/Inc",
"${workspaceRoot}/BLE_CNTR/Drivers/STM32L0xx_HAL_Driver/Inc/Legacy",
"${workspaceRoot}/BLE_CNTR/Middlewares/Third_Party/FreeRTOS/Source/portable/IAR/ARM_CM0",
"${workspaceRoot}/BLE_CNTR/Drivers/CMSIS/Device/ST/STM32L0xx/Include/",
"${workspaceRoot}/BLE_CNTR/Middlewares/Third_Party/FreeRTOS/Source/include",
"${workspaceRoot}/BLE_CNTR/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS",
"${workspaceRoot}/BLE_CNTR/Drivers/CMSIS/Include"
],
"defines": [
"_DEBUG",
"UNICODE",
"USE_HAL_DRIVER",
"STM32L051xx"
],
就可以用了。

2017年4月21日 星期五

FreeRTOS Coroutine的限制

MCU因RAM不足,去動Coroutine的方法,但不太順。有switch case存在時就會掛。
後來改為if else就好了。然後找到這篇;
http://www.freertos.org/co-routine-limitations.html
難怪很少人用,有坑。
用photothreads則沒有看到這個問題。
因為Coroutine也是由switch case做出來的,才會有此問題。
結論是,不要在switch case內使用crDELAY,就可以。那只好改成一長串的if else。

記下來,以免又採到坑。

2017年3月29日 星期三

事件驅動多工系統設計

規劃很久了,直到另一個功能出現才有動力去寫。寫出來程式不大。
系統只有二個檔案,測試一個,模擬一個。
event_drive.h 如下
extern void OS_ENTER_CRITICAL(void);
extern void OS_EXIT_CRITICAL(void);
extern void SimInit(void);

#define INIT_DEVICE() SimInit()
#define DIS_INTR() OS_ENTER_CRITICAL()
#define ENA_INTR() OS_EXIT_CRITICAL()

#define MAX_EVENT 8
#define MAX_TIMER 32

extern void execute(void);
extern void setTimeout(void (*p_func)(void), unsigned int tick);
extern void ISR_setTimeout(void (*p_func)(void), unsigned int tick);
extern void timerAction(void);

使用者可以設定同時執行的事件數目及要管理的延時事件數

event_drive.c 如下
#include "event_drive.h"

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

void execute(void)
{
    // FIFO function array
    if (eventInCnt != eventOutCnt)
    {
        eventFunc[eventOutCnt % MAX_EVENT]();
        eventOutCnt++;
    }
}

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

    if (!tick)
        tick = 1;
    DIS_INTR();
    for (i = 0; i < MAX_TIMER; i++)
    {
        if (delayCnt[i] == 0)
            break;
    }
    delayFunc[i] = p_func;
    delayCnt[i] = tick;
    ENA_INTR();
}

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

    if (!tick)
        tick = 1;
    for (i = 0; i < MAX_TIMER; i++)
    {
        if (delayCnt[i] == 0)
            break;
    }
    delayFunc[i] = p_func;
    delayCnt[i] = tick;
}

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

只有4個函式:
execute()是執行的地方,放在main()中的while(1)內就可以了。
timerAction()放在時間中斷內,用來管理延遲執行的函式何時要回復執行。
setTimeout()是使用者註冊一個延遲執行的函式。
ISR_setTimeout()是使用者用於中斷內的函式。

Sim.c windows下的模擬界面
#include <windows.h>
#include <winbase.h>

#include "event_drive.h"

HANDLE OSSemaphore;
DWORD WINAPI OSTickW32(LPVOID lpParameter);
HANDLE OSTick32Handle;

void SimInit(void)
{
    DWORD dwID;

    OSSemaphore = CreateSemaphore(NULL11NULL);
    OSTick32Handle = CreateThread(NULL0, OSTickW32, 00, &dwID);
    SetPriorityClass(OSTick32Handle, THREAD_PRIORITY_HIGHEST);
    SetThreadPriority(OSTick32Handle, THREAD_PRIORITY_HIGHEST);
}

DWORD WINAPI OSTickW32(LPVOID lpParameter)
{
    while (1)
    {
        timerAction();
        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, 1NULL);
}

測試用程式


#include <stdio.h>
#include "event_drive.h"

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

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

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

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

2017年2月8日 星期三

超級預測 心得

人類判定事情,多半不客觀。
只依自己的習慣、所知,就快速給出答案。

在研究大數據及追尋科學源頭過程中,不斷的發現人並不太使用數據做判定。
這也是為何大數據只要數據量大,找出來的就是比人下的判定要來得好。

得手"超級預測"一書,更是說明一件事,近代可能發生的事,可以由前期環境資料預測出來。
但人類仍不習慣使用客觀方式做分析。尤其是和自己相關的事物上。
大前研一的書也提出類似觀點。客觀分析才是正確的分析心態。

反問,是建立客觀的方法。
心態抽離也是方法。
這二個動作都不像是一般人會用的。

所以超級預測不是給出方法,而是給出心態上的建立。
也就是沒有正確的心態,就不會有正確的結果。
而大數據,它沒有心態上的問題,往往結果是正確的。反而人不見得會相信。

其實在一開始看這本書,心態上就會決定是否會讀完。
只想找出如何去學到"超級預測"的方法,結果是找不到,沒讀完就會放棄。
而我只看了半本,就發覺不對勁,書本不是沒有內容,而是另有表達。
所以讀此書,還是將心態放空。它不是教科書,讀法是不一樣的。

2017年1月13日 星期五

2016年MCU發展回顧

重回MCU,發現有一大堆新發展。

QSPI正式納入MCU標準:它不是新的介面,但在2016年出現了很多新裝置,使得MCU有很好的擴充性。除了原先的Flash外,今年還加入了FRAM,MRAM,SRAM等裝置。加上可以直接映射到內部空間。使用上變得很方便。

MIPI介面:VR應用下,總算使用了這個介面統一了Camera, TFT, Touch。圖型式人機界面開始統一。

Cordova開發工具成熟:MCU和手機利用此開發工具可以很快打造出可用的原型。相信APP和MCU一併開發會產生更多的應用。

RISC-V開源核心出現:在IOT需求下8051已不勘負荷,以BLE核心為例8051核心的應用就不再有發展,不然就要轉到Cortex-M0+。開源CPU核心就以RISC-V為主了。這個核心出現,只會加速將8051擠出IOT的應用。

2016年12月30日 星期五

Wifi module的戰役

在IOT未流行前,就已在使用了。當時算貴的,大部分在10鎂以上。
也有很多廠商,記得當時用了一家很大的,公司主要在上海,接觸的是台灣分公司。
但在使用上有些問題,也問過問題。不幸的回應不如預期,也來來回回的用mail在除錯。
後來問題無法有效解決,就換另一家的Module,研發在台灣,有問題借出電路,很快的找出問題在那。
於是就用了Wifi Module成功了第一個案子。
過了三年,沒想到IOT紅了,又回來看資料。什麼?ESP8266是那個?一個剩不到3鎂!記得不是開放原碼的,怎麼如今也開放了!
三年內類似功能的Module價格剩不到1/3,還不只一家做,大家都改用開放原始碼的Module。

現在在做BLE應用,看著各廠商的Module資料,又遇到了不開放原始碼的廠商,讓我想到Wifi Module的故事。
生意不是不能做,但真的不能用硬體的方式去思考。
程式碼是重要,但開放標準的元件,去鎖軟體能擋多久?你不開放,一堆其他公司就開放和你搶。
要不然,價格戰,相信市場很快就爛掉,誰也不想見(客戶除外)。
現在是軟體主導時代,應以軟體的角度去看市場。因為硬體廠商真的太多了!

2016年12月21日 星期三

發明?還是發展成功?

看人類科技發展,再加上經濟上的發展。
可以確定科技發明,並不等於發展。
往往發展人會變成發明人,再加上以前文字沒有留下明確記錄。發展人就直接變成發明人。
但發展就和發明不是直接相關了。
以中國4大發明來說,指南針和火藥就給西方人有效的發展。
火藥最為明顯。
其實又和其經濟效益有關。

砲: 石字,在中國發射的都是石頭。
而且和投石器常常混在一起。
火藥一定會是中國人發明,主因是煉丹。
但發展一定在地中海,主因是海戰。

早期砲身極重,只能放在車上移動,用來破城。但投石器也可以破城。
所以只能算是破城器之一。在很多的攻城器中不算特別突出。
傳到歐洲就不同了,大砲在陸地上不算太有用,在海上就不同了。
平射砲可以擊中船的吃水線,造成船底破洞,很容易使船隻失去功能。
一但用在海戰,直接變成殺手級兵器,不易移動及瞄準等缺點在船上也不是大問題。
於是大砲開始進化。從石砲彈變成鐵砲彈,那個時代鐵是高級物資,若非效果有差,怎可能做成消耗品?
大砲改變了船的地位,也開啟了人類放胆去探險的心,於是大航海時代就此展開。

發明又如何?
到後來發展才是重點。火藥改變了西方世界,再回頭改變了東方。回到東方已是另一個不一樣的東西了。