2022年9月30日星期五

[Ameba] RTL8720DN /BW16 二合一擴展板 Shield

支援兩款 RTL8720DN 開發板

  • A1 Pico - Kevin's Lab 
  • BW16 kit - Ai Thinker

 

 

規劃初衷

希望在實做Iot 應用作品時,可以很輕鬆的接入各種感測器及模組。並全力專心在程式開發上,減少在接線錯誤造成開發時間延宕。且同時保有擴展性,保留排針排及使用 Grove 連接器,使開發板增加擴展性。

硬體規格

  • 尺寸: 81.3 x 81.3 mm
  • 孔位 : Arduino uno 固定孔。
  • 電源輸入 : 6V ~ 18V 
  • 電源連接器: DC Jack 2.1(內正外負) , 可用變壓器(電流建議 >1A) 或是 2 顆 3.7V 鋰電池 (例如 18650) 串聯成 7.4V
  • Grove 接口 x 2 。 1 組 UART , 1 組 I2C

ESP32,BW16,RTL8720DN

BW16,RTL8720DN,ESP32



RTL8720DN,BW16,ESP32


支援外接模組

BW16,RTL8720DN,ESP32
  • PMS5003空氣偵測器
  • L9110S 模組 & TT 馬達
  • TFT LCD  / 240 x 320 Pixel
  • 伺服馬達
  • Buzzer
  • OLED SSD1306
  • RGB LED
  • MPU6050
  • HS-SR04 超音波
  • DHT20 溫溼度感測 / Grove 連接器
  • WS2812 LED


BW16,RTL8720DN,ESP32

注意事項

  • 接入開發板及模組時,請注意電源正負極方向,避免開發板及模組損壞
  • 使用 伺服馬達及 TT 馬達時,請務必使用 外接電源。有防呆機制,只使用 USB 5V 時,伺服馬達及 TT 馬達接口並不會有 5V 輸出。

如何購買

RTL8720DN 擴展板

 

相關

影片展示 :YouTube
開發板 : A1 Pico

 

2022年8月29日星期一

[PI PICO RP2040] HC-SR04 應用 @ C/C++

這個實驗是偶然搜尋到一個國外朋友使用 Raspberry pi Pico 控制 HC-SR04 的範例 Video (https://www.youtube.com/watch?v=5cWDgrbZers),我也想練習看看。順便優化他的程式 (https://github.com/KleistRobotics/Pico-Ultrasonic) 。

HC-SR04 是個 超聲波傳感器,可用來確認與物體的距離。偵測範圍可以到 2cm ~ 400cm 之間。以下是它的規格。

  • 電源: +5V DC
  • 靜態電流: <2mA
  • 工作電流: 15mA
  • 有效角度:<15°
  • 測距距離:2cm – 400 cm/1″ – 13ft
  • 測量角度:30度
  • 觸發輸入脈衝寬度:10uS TTL脈衝

信號傳輸和接收之間的時間能讓我們計算到物體的距離,因為我們知道聲音在空氣中的速度。

環境溫度 20ºC (68ºF) 時空氣中的聲速 = 343m/s

計算與物體的距離 = (行程時間 / 2) x 聲速

聲速為 343m/S = 0.0343 cm/uS = 1/29.1 cm/uS

HC-SR04 Spec. (來源 : https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf )

開始前必須在 Trigger 產生 10uS TTL 訊號, SR04 Module 便會自動產生 40KHz 聲波,接收回波後反映在 Echo pin 上,產生下緣信號。

PI PICO,SR04

在程式上


uint64_t sr04_sonic::getPulse(int trigPin,int echoPin)
{
    gpio_put(trigPin,1);
    sleep_us(10);
    gpio_put(trigPin,0);


    uint64_t width = 0;


    while(gpio_get(echoPin) == 0) tight_loop_contents();
    absolute_time_t startTime = get_absolute_time();
    while(gpio_get(echoPin) == 1){
        width++;
        sleep_us(1);
       if(width > timeout) return 0;
    }
    absolute_time_t endTime = get_absolute_time();
    return absolute_time_diff_us(startTime,endTime);
}


uint64_t sr04_sonic::getCM()
{
    uint64_t pulseLength = getPulse(this->trigPin,this->echoPin);
    return pulseLength /29.1/2; //or multiply by 0.0343
}

電路

完整程式碼

Github : https://github.com/cold63/Pico_C_Project/tree/main/sonic_sr04

 

2022年8月22日星期一

[PI PICO] Probe Debug 製作及使用

使用 C/C++ SDK 開發 Raspberry pi Pico 程式,編譯完成後產生 UF2 檔案。然後將這個檔案複製到 Pico 開發板上完成燒錄動作,就如同 Pi Pico 官方網站的示範展示 (https://www.raspberrypi.com/documentation/microcontrollers/c_sdk.html#your-first-binaries )。但若是頻繁修改的狀態下,這樣的操作方式就有點不方便使用了。

Pi Pico 還有如同其他 ARM 平台一樣有 SWD Debug port, 所以可以走這個路徑做板子燒錄及進行程式除錯。

在官方文件 (https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf ) 的 58 頁 (Appendix A: Using Picoprobe ) 及 62 頁msys, 說明了透過另一個 Pico 板 做為 Probe Debug 功能,及接線方法。

PI Pico RP2040

Debug Probe 電路

Pi Pico RP2040

J1 是 標準的 10 pin JTAG 連接器,預留。
J2 連接至 Pi Pico 的 SWD CLK 及 SWIO,如果需要有 printf 功能, 則分別接入 TX , RX。VSYS 可不用接,Target 的 Pi Pico 獨立接入 USB 做為電源輸入。

實物連接

PI Pico RP2040

Demo 影片

原始電路圖 及 Gerber

https://github.com/cold63/Pico_C_Project/tree/main/Debug_Probe

 

2022年8月14日星期日

[PI PICO RP2040] GPIO Function 功能測試 @ C/C++

Raspberry Pi Pico 具有 26 個 GPIO 引腳,GPIO 也是在 MCU 中最基本運作的基礎. 這裡開始打算用一個 C/C++ SDK 程序 對 GPIO 的操作測試。程式文件在 Raspberry 官方網站上都有提供,可以在這個頁面下載. ( https://www.raspberrypi.com/documentation/microcontrollers/c_sdk.html )

官方的範例有個名為 hello_7segment 的程式範例,我這裡將改成用 hello_7segment 內使用的方法,來做跑馬燈的功能。並有 Button 中斷控制做啟動及停止。

電路

RP2040,raspberry pi pico

電路中的 LED 是從 GP2 接到 GP9 ,共 8 個 LED。GP10 接一個彈跳開關。



主程式碼


int main(){


    stdio_init_all();
    
    for(int x = Shift_GPIO; x < Shift_GPIO + 8; x++){
        gpio_init(x);
        gpio_set_dir(x,GPIO_OUT);
        gpio_set_outover(x,GPIO_OVERRIDE_INVERT);
    }
    gpio_set_irq_enabled_with_callback(10,   GPIO_IRQ_EDGE_FALL, true, &gpio_callback);


    gpio_init(PICO_DEFAULT_LED_PIN);
    gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);


    uint8_t y;


    while(true){
        
        if(OnButton) {
            uint32_t mask = bits[y] << Shift_GPIO;


            gpio_set_mask(mask);
            sleep_ms(1000);
            gpio_clr_mask(mask);


            y++;
            if(y >= 8){
                y=0;
            }
        }

    }


    return 0;
}

Button 按鍵副程式


void gpio_callback(uint gpio,uint32_t events){


    if(events == 0x4)
    {
        if(OnButton){
            OnButton = 0;
            gpio_put(PICO_DEFAULT_LED_PIN, 1);
        }
        else{
            OnButton = 1;
            gpio_put(PICO_DEFAULT_LED_PIN, 0);
        }
    }
}

呈現的結果是
按 Button 開始跑馬燈 , GP25 LED 不亮
再按 Button 停止跑馬燈, GP25 LED 亮起

gpio_set_outover : 設定 GPIO 輸出模式 ,一般 / 反向 / HIGH / LOW 。 程式是 設定反向
gpio_set_mask : 致能 GPIO 不被改變, 直到執行 gpio_clr_mask, 這與 gpio_put 用法不同。

範例程式

https://github.com/cold63/Pico_C_Project/blob/main/gpio_1/main.c


 

2022年8月9日星期二

[STM32] FreeRTOS 手動移植至 CubeIDE 過程記錄

FreeRTOS 是一種即時作業系統,非常適用於微控制器應用。當然 STM32 也是在其中最適合於 FreeRTOS 操作的微控制器,這次來介紹 CubeIDE 環境中如何手動加入 FreeRTOS 系統。這次使用的開發板是 NUCLEO-L476RG,IDE 是 CubeIDE。

下載 FreeRTOS

在 FreerRTOS (https://www.freertos.org/) 直接下載,目前是 FreeRTOSv202112.00 這個版本

STM32,FreeRTOS

建構 FreeRTOS

下載後,解開壓縮檔。有幾個資料夾及檔案 (FreeRTOS,FreeRTOS-Plus,tools .....etc),我們只要 " FreeRTOS " 這個資料夾及內容。我採取的是刪除法,先建立一個空的資料夾,然後將 FreeRTOS 複製到剛建立的資料夾內。

複製完成後,直接在這個臨時資料夾內操作。

FreeRTOS 資料夾內有 Demo , License , Source , Test 等等內容。保留 License , Source,其他都刪除。

直接到 Source\portable 內 ,保留 GCC , 及 MemMang 這兩個資料夾,其他刪除。

L476RG 是個 M4 及含 FPU 運算的微控制器,所以

在 Source\portable\GCC 內, 只保留 ARM_CM4F 資料夾。

回到 MemMang 內
保留 heap_4.c , 其餘刪除

到這裡我們需要的檔案已經完成了。

CubeIDE 開啟新專案

我們設定 2 個 GPIO-OUT , 分別是 LD1 & LD2

STM32,FreeRTOS

在 NVIC 中斷設定, 優先權設為 NVIC_PriorityGroup_4

STM32,FreeRTOS

接著產生 BSP code。

調整

產生 BSP code 後,開始做相對應的設定。
複製 FreeRTOS code。

在 "建構 FreeRTOS" 所以建立的資料夾, 直接用拖拉的方式。複製到 CubeIDE 左側的 Project Exploper。

STM32,FreeRTOS

開啟 Project / Properties 對話框

找 C/C++ General / Paths and Symbols , 分別在 Includes , Source Location 這兩個標籤 (Tab) 設定

Includes :

FreeRTOS/Source/include
FreeRTOS/Source/portable/GCC/ARM_CM4F

STM32,FreeRTOS

Source Location :

加入 FreeRTOS/Source

STM32,FreeRTOS

修改 stm32l4xx_it.c


void SysTick_Handler(void)
void PendSV_Handler(void)
void SVC_Handler(void)

3個 function 用 /**/ 注釋掉

建立 FreeRTOSConfig.h


在 FreeRTOS 中找到
FreeRTOS/Demo/CORTEX_M4F_STM32F407ZG-SK/ FreeRTOSConfig.h
複製到 專案資料夾的 Core/Inc 內


內容做小修改


#ifdef __ICCARM__
    #include 
    extern uint32_t SystemCoreClock;
#endif

改成符合 CubeIDE


#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include 
    extern uint32_t SystemCoreClock;
#endif

以下 2 個參數改為 0


#define configUSE_IDLE_HOOK                0
#define configUSE_TICK_HOOK                0

範例: 測試點亮 LED

到這裡, 開始寫 code
首先在 main() 前複製 這 2 個空 function


void vApplicationMallocFailedHook( void )
{
    /* vApplicationMallocFailedHook() will only be called if
    configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
    function that will get called if a call to pvPortMalloc() fails.
    pvPortMalloc() is called internally by the kernel whenever a task, queue,
    timer or semaphore is created.  It is also called by various parts of the
    demo application.  If heap_1.c or heap_2.c are used, then the size of the
    heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
    FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
    to query the size of free heap space that remains (although it does not
    provide information on how the remaining heap might be fragmented). */
    taskDISABLE_INTERRUPTS();


    for( ;; );
}




void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
    /* This function will get called if a task overflows its stack.   If the
    parameters are corrupt then inspect pxCurrentTCB to find which was the
    offending task. */


    ( void ) pxTask;
    ( void ) pcTaskName;


    for( ;; );
}

我們有 2 個 LED , 所以分別用 2 個 Thread 控制


static void Blink1_Task(void *pvParameters)
{
TickType_t xlastFlashTime;
xlastFlashTime = xTaskGetTickCount();


while(1){
     vTaskDelayUntil(&xlastFlashTime,500);


     HAL_GPIO_TogglePin(GPIOA, LD1_Pin);


}


}


static void Blink2_Task(void *pvParameters)
{
TickType_t xlastFlashTime;
xlastFlashTime = xTaskGetTickCount();


while(1){
     vTaskDelayUntil(&xlastFlashTime,500);


     HAL_GPIO_TogglePin(GPIOA, LD2_Pin);


}


}

在 main()


  xTaskCreate(Blink1_Task,"Blink1",128,NULL,1,NULL);
  xTaskCreate(Blink2_Task,"Blink2",128,NULL,2,NULL);
  vTaskStartScheduler();

執行效果是這 2 個 LED 看起來會像是同時間點亮。


範例 Source code 放在 Github,
https://github.com/cold63/STM32_Code/tree/master/Freertos_M4F

 

2022年7月12日星期二

[PI PICO RP2040] 開始第一個程式 @ C/C++

當我們拿到一個新的板子時,通常會點 LED 及 print 顯示。 然後再做各種的範例測試,這做為 Raspberry Pi Pico RP2040 & C/C++ 開篇以來,也從這裡做為開始吧。

Raspberry Pi Pico RP2040 板的 print 列印顯示 UART (Default) 輸出為 UART 0 ,也就是深紫色的 UART0_TX (1) 及 UART0_RX。Default Baudrate 為 115200bps。

PI PICO RP2040


 // Enable UART
 stdio_init_all();
 

對 UART及 USB 做 初始化,後續可用 stdio 函式。例如: printf(),scanf()...等

Blink 與 printf 實作


int main() {
    // Enable UART
    stdio_init_all();


    gpio_init(25);
    gpio_set_dir(25, GPIO_OUT);    
    
    while (true) {
        gpio_put(25, 1);
        sleep_ms(1500);
        gpio_put(25, 0);
        printf("blink test\n");
        sleep_ms(1500);
    }


    return 0;
}

UART0_TX (1) 及 UART0_RX 連接到 USB TO UART 轉換器 開始接收字串

如果要使用 USB CDC 功能,只要修改 cmake (CMakeLists.txt) 檔案即可


pico_enable_stdio_usb(newblink1 1)
pico_enable_stdio_uart(newblink1 0)

即 usb enable , uart disable

裝置管理員

PI PICO RP2040

putty 的 serial 設定

PI PICO RP2040

輸出

PI PICO RP2040

原始碼連結

https://github.com/cold63/Pico_C_Project/tree/main/newblink1

 

2022年6月10日星期五

[Ameba] 使用Arduino Wire 基本函式存取 24C02 EEPROM / I2C

什麼是 EEPROM ?

EEPROM 代表電子可擦除式可做讀寫的存儲器。它允許在使用非常少的功率的情況下長時間寫入和存儲值。大多數微控制器甚至在其電路中直接有 EEPROM,例如 ATmega328P(Arduino Uno 芯片),它有 1KB。但如果這還不夠呢?SD 卡具有更大的存儲容量,但也更複雜、體積更大且耗電量更大。

這次的範例使用 Arduino 的 Wire 基本函式, 不套用現成 Library 。從實做中理解控制原理。這次選用型號為 AT24C02B / 儲存空間 2Kbit

Datasheet ( https://ww1.microchip.com/downloads/en/DeviceDoc/doc5126.pdf)

輸出腳位

24C02,Arduino

開發板

此次使用的是 自行開發的 A1 Lite / Realtek RL8720DN 。連結在此 (連結) ,在這就不多做介紹。
在 A1 Lite 使用 I2C 前先將預裝的提升電阻用焊接的方式將 JP2 , JP3 短接起來

A1 Lite,Arduino,RTL8720DN,BW16

接線

AT24C02ConnectA1 Lite
A0GND 
A1GND 
A2GND 
GNDGNDGND
SDA 8
SCL 7
WPGND 
VCC3V33V3

EEPROM I2C 位址

位址為 7-bit 規則 , A0 ~ A2 均接地。 所以位址為 0x50

 

寫入資料

Ameba,I2C

我們要先確認 WP 是否接入 GND。首先送出 EEPROM 的設備位址,0x50 ~ 0x57 之間。根據接線需送出 0x50 (若設備得到正確位址會有 NACK/ACK 反饋)。接著送出數據位址,再送出資料,最後發出 STOP 訊號 endTransmission() 告知 EEPROM 不再繼續。

程式碼


void WriteByte(uint8_t data_addr, uint8_t data)
{
 
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write(data_addr);
  Wire.write(data);
  Wire.endTransmission();
}

讀取資料

Ameba,I2C

首先要先送出 EEPROM 設備位址 及 數據位址。接下來再送出 設備位址,EEPROM 會反饋 1 組(Byte)資料。

程式碼


uint8_t ReadByte(uint8_t data_addr)
{
  uint8_t data;
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write(data_addr);
  Wire.endTransmission();
  Wire.requestFrom(EEPROM_ADDRESS,1);


  if(Wire.available())
  {
    data = Wire.read(); 
  }
  Wire.endTransmission();
 
  return data;
}

綜合以上,組成


  WriteByte(1,0x5A);
  delay(10);
  
  Serial.println(ReadByte(1),HEX);

輸出結果

進階

以 AT24C02 來說, 它是由 8 bytes 組成 一個 page, 以這個型號有 32 page。它可以一次寫入讀取最多 8 bytes 的資料, 我們將改寫程式

寫入資料



void WriteBytes(uint8_t data_addr, uint8_t *data,uint8_t len)
{


  uint8_t x;
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write(data_addr);
  for(x = 0; x < len; x++)
  {
    Wire.write(data[x]);  
  }
  
  Wire.endTransmission();
}

讀取資料


void ReadBytes(uint8_t data_addr,uint8_t *data, int len)
{
  uint8_t x;
  Wire.beginTransmission(EEPROM_ADDRESS);
  Wire.write(data_addr);
  Wire.endTransmission();
  Wire.requestFrom(EEPROM_ADDRESS,len);


  if(Wire.available())
  {
    for(x = 0; x < len;x++)
    {
      data[x] = Wire.read();    
    }
    
  }
  Wire.endTransmission();
  
}

輸出結果

Ameba,I2C

 

 

GitHub 完整程式碼

連結 ( https://github.com/cold63/Arduino_Code/tree/main/I2C_EEPROM )

其他參考

TI 應用手冊 Understanding the I2C Bus (SLVA704 )
連結 ( https://www.ti.com/lit/an/slva704/slva704.pdf )