MCU單晶片韌體設計

2022年12月31日 星期六

佈署AI模型於Web 上


目標: 用瀏覽器上傳圖案到Web後端進行預測, 並將模型預測結果回傳至瀏覽器。


#teachable machine #Flask  #Keras 

#Install required packages
pip install flask==2.1.1
pip install Pillow==9.1.0
pip install tensorflow==2.3.1
pip install keras==2.4.3






專案目錄結構如下, 其中model 資料匣 要放置AI 模型檔及Label 文字檔。凡應用是上傳圖片,由模型預測分類結果的, 都可以套用本專案程式架構。在不想改程式碼, 就直接模型檔名改成keras_model.h5 ,類別的文字檔改成 labels.txt。 


 執行主程式 main.py 後, 會載入模型同時啓動Web Server (Flask) 



P.S. 此處 model 資料匣的所放的AI模型, 是直接使用 Teachable Machine 來建立模型。為了方便套用至其他的應用程式, 從teacbable machine 複製來的程式碼, 將其程式架構改寫為 Class 的方式,會比較好用。而且主程式會顯得很簡潔也會易於日後程式維護。aimodel.py 程式碼參考如下:



 

2022年12月1日 星期四

[Python] Python的變數僅僅只是一個tag

 

在python 世界裡, 宣告的變數僅僅只是一個tag。而tag 可以到處貼, 所以當你問 tag 的資料型態時 , 那就是在問tag 當下所貼的位置的物件資料型態為何  ?  

a=3  , 則 type(a)==> int

b=3.14  , 則 type(b)==> float

c="hello"  , 則 type(c)==> str

3, 3.14, "hello" 這都是物件, 佔有空間 ,而a, b, c 就是tag name, 只是一個名字用來存取物件而已。

python 的變數完全不同於C/C++ 變數的概念。C/C++ 變數是佔有空間的, 空間存放著資料, 而空間有多大就決定了資料的數值範圍。

int a=64;   (佔4個bytes)

char ch='A';  (佔1個bytes)





Python 有Garbage collection 的機制, 故物件10沒有任何tag參考, Python 會自己回收。
Python 中的List , 它是一個container ,即它是具有一個空間。 如 a=[3,3,1] , a[0] 這個tag 指向物件3,  a[1] 這個tag 也指向物件3, 而 a[2] 這個tag 指向物件1



你可能會問一個問題, Python 的變數用這樣搞有什麼好處?

用個例子說明好了,  a=[1,2,3] 

若要複製一份給c, 執行 c=a.copy() 就會將a的container 表格複製給c, 因為只是複製了container a 表格, 和資料物件多大沒有關係, 所以可以很快,也不用將相同的資料物件在記憶體中放兩份。若是C/C++ 則a, c 是各別的空間, 因此即使是相同的資料,在記憶體中也得各自存放一份,會比較佔空間,而且在複製資料時也得一個個byte 複製過去 ( memcpy),速度上也比較慢。






相關文章:

2022年11月5日 星期六

[Notepad ++]新增GNU ARM Assembly 語言格式

 

在Notepad ++編輯器新增GNU ARM Assembly 語言格式


1)下載  ASM for ARM GNU語言包 user defined languages


2) 在[語言]->[定義程式語言] 然後, 匯入ASM for ARM GNU 語言包



3) 匯入後可以再去修改, 例如, 原本ASM單行註解為只有 ; @ , 可再加入// (GNU GCC 是看得懂//為註解語法)

2022年11月1日 星期二

2022年10月7日 星期五

[Python] Why do we need frozenset ?

(1) 用frozenset 才可以用集合當作Key

Example:

itemsets=[{'B','C'},{'D'}] 

count[{'B','C'}]+=1  # Error : "unhashable type: 'set'"

in this case, we can use frozenset to make 'set' as a key

count[frozenset({'B','C'})]=1   

(2) 用frozenset 才可以做集合包含集合

  S=set()

e={'A','B','C'}

S.add (e)  ==> 想要表示 S={{'A'},{'B'},{'C'}} --> TypeError: unhashable type: 'set'    

S.add (frozenset(e))  -->OK   S={frozenset({'A', 'B', 'C'})}


2022年8月29日 星期一

[Raspberry Pi ] 查詢 Software and Hardware Version of a Raspberry Pi

 

How to Check the Software and Hardware Version of a Raspberry Pi

 Type the following commands , you will get all information about Raspberry Pi
  • cat /etc/os-release
  • uname -a
  • cat /proc/cpuinfo | grep Model



 2019 年發布的Raspberry Pi 4  ,被發現有 USB-C 的充電問題,而小改款  v1.2 解決了此問題! 

2022年8月12日 星期五

[Linux 程式設計] 關於GCC

 

1. 後面的-lxxxx 如果是linux他的位置在哪裡? 

(base) ubuntu@ubuntu1804:/usr/lib$ cat  /etc/ld.so.conf.d/x86_64-linux-gnu.conf


# Multiarch support
/usr/local/lib/x86_64-linux-gnu
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
(base) ubuntu@ubuntu1804:/usr/lib$ pwd
/usr/lib

2. 標準函式庫為何不用帶-lxxx

 因為gcc 預設會連結標準函式庫 libc.so.xx

3. 如果使用opensource 專案時要使用 -lxxxx 這部分該怎使用如果他的lib名稱 不是lib<project>
 
  如果不是標準名稱就得用library全名. 主要還是要指定 -L<lib目錄>  , 指名library的位置, 如果不是放在library 的搜尋路徑上的話



(base) ubuntu@ubuntu1804:~$ gcc -v

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)


----------
相關課程: 
https://www.ittraining.com.tw/ittraining/it-elearning/el-linux-embedded/e-linuxsys#tab01

2022年8月1日 星期一

Jupyter notebook 延伸工具

 

超好用的2個Jupyter notebook 延伸工具
  • Table of content : 針對Markdown cell 提供目錄
  • autopep8:  python代碼格式化工具






(2) 安裝 Jupyter notebook extensions

打開Anaconda Prompt  , 執行

pip install jupyter_contrib_nbextensions && jupyter contrib nbextension install

(3) 重新開啓Jupyter Notebook, Enable "Table of content "






2022年7月6日 星期三

[Linux 系統程式設計] 關於sigaction 的 SA_RESTART flag

 

Linux 系統程式設計


 #include <signal.h>

       int sigaction(int signum, const struct sigaction *restrict act,
                     struct sigaction *restrict oldact);
   The sigaction structure is defined as something like:

           struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };

在sigaction結構中, 有一個 sa_flags 欄位可以設定為 SA_RESTART , 這代表什麼意思呢? 原文如下
SA_RESTART     
       If a blocked call to one of the following interfaces is
       interrupted by a signal handler, then the call is automatically
       restarted after the signal handler returns if the SA_RESTART flag
       was used; otherwise the call fails with the error EINTR.


例如, Socket programming 的 accept() 就是一個blocked system call,當程序停留在這個系統呼叫時, 若收到signal 則會跳到對應的signal handler去執行, 那signal handler 執行完成後呢? 

其結果可以是繼續回到原呼叫 accept() 的狀態, 就好像沒有跳出去一樣,  或者讓 accept() 直接返回, 並且返回錯誤碼為 EINTR .

OK, 那要繼續回到原呼叫 accept() 的狀態,,可以在sigaction結構的sa_flags 設定SA_RESTART , 再呼叫sigaction() 中進行設定即可

       
    struct sigaction sa;
   sa.sa_handler = &signal_handler;
   sa.sa_flags = SA_RESTART;
   sigfillset(&sa.sa_mask);
   if (sigaction(SIGUSR1, &sa, NULL) == -1) {
      fprintf(stderr,"error\n");
   }

2022年6月25日 星期六

UART over TTL/RS232

 

UART 是軟體層面的 serial 通訊協議(也可以借力 UART IC來完成)。定義baudrate, start bit, stop bit , data bit, parity check 等等, 但這些0和1都是只邏輯的0和1。而實際走的硬體訊號, 則要看使用的是TTL還是 RS232。TTL和 RS232 描述的是 Physical 電氣訊號。

TTL (transistor-transistor logic) 就是定義 0V 為 0,Vcc 為 1 , 一般 MCU、SoC 都會用的方式。  RS-232 定義 -3 to -25V 為 0, 而+3V~+25V為1。不過 RS232 是一個完善的標準通訊規範,所以尚包含硬體流量控制的機制及 Connector 的型式(如DB-9) 等內容。正常的PC 用的就是RS232 界面。不過若僅僅只是做基本的傳輸,不是拿來接數據機(Modem)這類的,其實也只是用了其中3條通訊線而已,TXD, RXD, GND。現在你懂了,為何 UART over TTL 只有3條訊號線的原因。

Source image: https://components101.com/


PC(RS232)—----- UART ——MCU (5V), 因為電壓不同所以要做level shifter , 這可以使用MX232之類的IC來完成. UART over RS-232 (上) 及 UART over TTL (下) 傳送 01010101的電壓圖。總之,我送0/1, 你要解讀成0/1, 而不是解讀成1/0。
Source Image: https://www.sparkfun.com/

相關文章: 


相關課程: 
[1] Linux 驅動程式設計 -實作LINUX UART/TTY Driver
[2] ARM Boot loader 設計-實作UART
[3] MUC 韌體設計-UART驅動

2022年6月22日 星期三

[C語言]字串處理函式:strspn, strpbrk



size_t strspn(const char *str1, const char *str2)  傳回str1包含了str2 字串中的字元,共有有多少個。
char *strpbrk(const char *str1, const char *str2)  傳回str1中出現str2字串中字元的位置。若沒有找到傳回NULL. 

char *d =strpbrk("my phone number is 23167736", "0123456789")
print("%c",d); ==> 卬出2

========================

 以處理HTTP header 的字串為例,  我們要逐行取出HTTP header的內容,  但要如何逐行進行呢? 
以下是使用 strspn(), strpbrk() 函式來完成的
 




參考: 
[1]程式參考


[2]   https://github.com/troglobit/merecat/blob/master/src/libhttpd.c




2022年5月30日 星期一

Disables dynamic cpufreq

 



Boot loader程式放入 Pi3中, 一開機剛開始跑的時候,LED 閃爍頻率都很正常 , 但大約經過約10秒左右 , 時間會變快 . 例如LED 0.5sec閃爍一次 , 經過10sec後變快小於0.5sec閃爍,是哪裡的設定需要再做調整修改 ?



#Disables dynamic cpufreq driver

add this line "force_turbo=1" to config.txt  . 

you can also google DVFS to get more information


2022年5月24日 星期二

[ C 語言] gcc 定義巨集

 

[ C 語言]

1.) 在程式檔中 (,c 或.h) 定義 DEBUG  

  #define DEBUG  

 



2.) 不改變在程式檔, 而是在程式編譯階段去定義 DEBUG    

gcc -DDEBUG  debug.c -o test 

另外也可以設定 DEBUG的值, 如 gcc -DDEBUG=4 debug.c -o test

(以上等同在hello.c 內加入了 #define DEBUG 或   #define DEBUG  4 這一行 )

其實, 若 寫 -DDEBUG  隱含  -DDEBUG=1 的意思 


注意: 若程式內及gcc 都同時定義了 DEBUG 這個符號 
,  會以程式碼內寫的為主。(會出現重覆定義的warning 訊息)

pi@ittraining:~/LinuxPro/trunk/source/ch3 $ gcc debug.c -DDEBUG=1 -o test

debug.c:4: warning: "DEBUG" redefined

 #define DEBUG 3

<command-line>: note: this is the location of the previous definition






2022年4月30日 星期六

[C 語言] 有無const 的差異?

 


char *s : 表示s 指標指向一個character
constant char *s : 表示s 指標指向一個constant character; 也就是所指向的字元不能被修改
可以參考底下範例, 觀察有無const 的差別.

#include <stdio.h>
int main()
{
const char str[]="hello";
str[0]='H';
printf(str);
return 0;

}

若是寫 const char *str="hello";
這str 本來就指向read only 的"hello"字串區域, 所以本來就不能更改, 因此
這兩個寫法結果沒有差異, 但用const char * str寫法可以讓別人知道, 不會透過str 來改變指標所指的內容.

char *str="hello"; 
const char *str="hello";


2022年3月29日 星期二

什麼是機器學習? (學習簡介)



訓練出好的AI模型的下一步是什麼 ? 就是AI佈署(Deployment ) , 你可以將AI模型佈署在雲端 或者佈署在邊緣的嵌入式的裝置上, 而嵌入式的裝置可以是指特定的微控制器上或是Android/iOS 手機上。












 

2022年3月15日 星期二

[MCU單晶片 Q&A] ADC工作頻率

 

Question:
要怎麼知道Fosc 是16MHz呢? Fosc 是MCU的固定property 還是是個可以設置的參數呢?

Answer: 
這是外部提供 16MHz 的 Crystal oscillator
p.s. 可參考上課文件的的電路圖  (WengPICV2_sch.pdf )


2022年3月13日 星期日

[MCU單晶片 Q&A] 中斷

 

Question:

PPSunlock() 和PPSlock() 功能為何呢? 為什麼要用這兩個PPSunlock和PPSlock去包住RPI function? 使用PPSlock()和PPSunlock() 為什麼要把GIEH 中斷關掉呢? 因為沒看到文件上有這樣說明, 但是PPS 裡的function 有關掉中斷後面再回復的動作




Answer: 

   這是PPS 使用的規定, 如此才可以 remap Pin 腳功能, 
   可以參考PIC18F46J50 文件描述, 關於PPS 主題 10.7.4.1 Control Register Lock  

2022年3月9日 星期三

[MCU單晶片 Q&A] I2C 操作


[I2C 操作]
Question : 在I2C的START function 裡要先檢查SDA 是否已經為0,來決定是否進行後面是否要將SCL=0和SDA=1的動作,這樣和範例是藉由Din 來判斷是一樣的嗎? 而 Din 是SDA接腳的接收輸入接腳,為什麼要定義這個接腳呢?而沒有SCL的輸入接腳的定義




Answer : 
確認SDA 是否真的在Low level的狀態, 實際的作法是去讀取PORT 暫存器, 而不是去讀取TRIS暫存器. 為何在I2C START時,要判斷SDA為LOW呢? 因為我們進行I2C START動作, 是將SDA=1 (而原本SCL若在High), 則會變成多產生一個I2C STOP的動作,才再產生I2C START的動作。






Each port has three registers for its operation. These registers are:
  • TRIS register (data direction register)
  • PORT register (reads the levels on the pins of the device)
  • LAT register (output latch)





2022年2月25日 星期五

PCB Layout 入門教學(八) ---PCBA 人工打件


PCB 佈線圖完成後,產生所謂Gerber File 給PCB 加工廠後,就可以生產出PCB 電路版了。接著就是照BOM表的電子零件清單備料。當然也會有統包的公司,包含PCB、備料、打件、樣品生產的服務。一個PCB空板經過SMT打件,或經過DIP插件的整個製程,簡稱PCBA (PCB Assembly)。

SMT 自動打件的流程為:製作鋼板、PCB板定位、上錫膏、貼裝機貼裝、過回焊爐、成品檢驗。但如果是原型樣品,或僅需小批量生產,如100~200片,想要試試看"人工打件",就是沒有SMD貼裝機啦,那你也可以自行DIY,本篇文章就是要分享人工打件的方法,適合Maker 族群。


(1) 製作鋼板: 為PCB 板製作一個鋼板,這是一次性的成本。鋼板上有洞的地方就是等等要上錫的位置。


 
 

(2)上錫膏:

 

將錫膏均勻抹平在鋼板的洞上,拿掉鋼板後如下圖所示。



(3.) 人工貼裝機: 依照Layout 圖,將元件正確擺放。在融錫前,錫膏的黏度剛好可以稍微黏住PCB表面的電子零件,所以有些微的晃動也不會使元件偏移。
 




(4.)  手工迴銲爐: 需要一個加熱台來加熱融錫,如此電子零件就被銲接在PCB上了。










(5.) 成品:
  
    大功告成! 每一個零件就像由機器自動定位來擺放一樣。好吧! 這就人工打樣的過程 ^_^ 





額外分享:
 
這是專業SMT機台的打件速度~



 
上錫膏也是自動化流程的一部份





2022年1月21日 星期五

機率

 

Random variable 

  1. A discrete random variable X is a quantity that can assume any value x from a discrete list of values with a certain probability.
  2. The probability that the random variable X assumes the particular value x is denoted by Pr(X = x). This collection of probabilities, along with all possible values x, is the probability distribution of the random variable X.

Ex. Sum of two dices

X=4 ==> (1,3), (2,2) (3,1)


Discrete Probability Rules
  1. Probabilities are numbers between 0 and 1: 0 ≤ Pr(X = xk) ≤ 1 for all k
  2. The sum of all probabilities for a given experiment (random variable) is equal to one: 
  3. The probability of an event is 1 minus the probability that any other event occurs: 

Ex. Sum of two dices

Pr(X=3) = 2/36     ,   Pr(X=4) = 3/36     





Cumulative Distribution Function of a Discrete Random Variable
The cumulative distribution function (CDF) of a random variable X is denoted by F(x), and is defined as F(x) = Pr(X ≤ x).

Using our identity for the probability of disjoint events, if X is a discrete random variable, we can write

where xn is the largest possible value of X that is less than or equal to x







Binomial PDF
If X is a binomial random variable associated to n independent trials, each with a success probability p, then the probability density function of X is:

where k is any integer from 0 to n. Recall that the factorial notation n! denotes the product of the first n positive integers: n! = 1·2·3···(n-1)·n, and that we observe the convention 0! = 1.


Definition: Expected Value of a Discrete Random Variable
The expected value, , of a random variable X is weighted average of the possible values of X, weight by their corresponding probabilities:

where N is the number of possible values of X.

References: