Bài 04. Giao tiếp với OLED 0.96 inch SSD1306.

Bài 04. Giao tiếp với OLED 0.96 inch SSD1306.

Bài 04. Giao tiếp với OLED 0.96 inch SSD1306.

  1. LÝ THUYẾT.
  2. Xin chào các bạn,

    Hôm nay mình xin chia sẻ một số thông tin và hướng dẫn sử dụng OLed 0.96 inch SSD1306. Hiện tại trên thị trường có rất nhiều loại oled 0.96 inch với các thông số như chip điều khiển(SSD1306, SSD1325, SSD1331, SSH1106..) và chuẩn khác nhau(I2C, SPI..). Ở đây mình xin chia sẻ thông tin về oled 0.96 inch sử dụng chip điều khiển là SSD1306 và sử dụng chuẩn giao tiếp I2C.

    Mục đích chính của oled là để hiển thị thông tin với màn hình nhỏ và thông tin tương đối rõ ràng, chúng ta có thể sử dụng chúng với một số ứng dụng như: hiển thị thời gian, hiển thị thông số nhiệt độ, độ ẩm để theo dõi, hiển thị thông tin cho robot, các thiết bị cầm tay nhỏ gọn… Một vài thông số cơ bản :

    • Sử dụng chip điều khiển SSD1306.
    • Sử dụng chuẩn giao tiếp thông dụng I2C nên tương thích với hầu hết các loại MCU có trên thị trường.
    • Kích thước màn hình 0.96inch(128x64 điểm).
    • Công suất tiêu thụ 0.08W.
    • Điện áp cung cấp 3 - 5VDC.
    • Góc hiển thị > 160 độ.
    • Màu hiển thị trắng/xanh dương.
  3. Code với MX cube.
  4. Sơ đồ kết nối:

    Một số lưu ý khi sử dụng module:

    • Loại ARM sử dụng là STM32F103C8T6, 48 pin out, clock là 72Mhz, Flash memory 64 Kbytes.
    • OlED 0.96 inch , giao tiếp I2C.
    • Địa chỉ của OLED này khi giao tiếp I2C là 0x78.
    • Giao tiếp I2C với mode Standard speed (100 Khz).
    • Trình biên dịch là Kiel C V5, thư viện sử dụng là thư viện HAL( HAL libraries).
    • Hàm ssd1306_refresh_gram(); được sử dụng để làm mới màn hình, hiển thị những thông tin mới ghi vào bộ nhớ.
    • Sử dụng hàm ssd1306_draw_bitmap() để vẽ các kí tự, ssd1306_draw_3216char() hoặc ssd1306_draw_1616char() để ghi các kí tự với font khác nhau, ssd1306_display_string() để hiển thị chuỗi kí tự với các thông số input tương ứng.
    • Bộ thư viện mình tìm được trên mạng và đã chỉnh sửa lại. Để xem thêm các function liên quan về OLED thì các bạn có thể vào tab Function như hình ở dưới.
    1. Cấu hình dung Mx Cube:
      • Cấu hình xung clock:
      • Cấu hình chân debug.
      • Cấu hình I2C ở chế độ standard mode, tốc độ là 100khz, port I2C2.
      • Cấu hình xung clock hệ thống Max là 72Mhz, giúp tốc độ xử lý lệnh là nhanh nhất.
      • Cấu hình trình Ide và code generate -> click button generate code.
    2. Modify code generate:
      • Copy thư viện từ project download sang project của bạn trong thư mục src and inc. Thư mục src : file Fonts.c, SSD1306.c. Thư mục inc: MacroAndConst.h, Fonts.c, SSD1306.c.
      • Add các file .c vào project của bạn.
      • Include các thư viện vào file main.c, lưu ý add vào giữa các dòng command code BEGIN và END để tránh mất code khi generate code lại tự Mxcube.
      • Modify code để ghi một số ký tự mẫu lên oled.
      • Cấu hình reset and run để code được thực thi khi flashing code mà không cần nhấn nút reset.

      Note: Đây chỉ là ví dụ cơ bản để hiện thị một số ký tự lên oled, các bạn có thể tự tìm hiểu và modify code để có những ứng dụng riêng của mình. Mọi thắc mắc các bạn có thể comment hoặc inbox mình, mình sẽ trả lời nhanh nhất trong thời gian có thể.

  5. Một số link tham khảo.
    1. Một số link mua hàng các bạn có thể tham khảo.
    2. Link 1 Link 2 Link 3
    3. Link download tài liệu.
    4. Download datasheet của chip điều khiển SSD1306 : Download các file thư viện :

01. Giao tiếp với cảm biến ánh sáng BH1750.

Giao tiếp với cảm biến ánh sáng BH1750.

01. Giao tiếp với cảm biến ánh sáng BH1750.

  1. LÝ THUYẾT.
  2. Với BH1750 chúng ta có thể tạo được nhiều ứng dụng tiện lợi trong đời sống như bật tắt đèn ngoài sân khi trời tối, ứng dụng bật đèn cho nông nghiệp… , là ic dùng trong điện thoại, tivi. So với quang trở(điện trở thay đổi theo ánh sáng) thì BH1750 có độ chính xác và dải đo rộng hơn, tuy nhiên quá trình đo đạc cũng phức tạp hơn.

    BH1750 dùng chuẩn giao tiếp I2C, dải đo từ 1 – 65535 lux. Lux là đơn vị đo ánh sáng. Dành cho những bạn chưa biết về đơn vị lux : https://vi.wikipedia.org/wiki/Lux

    Một số tính năng của IC:

    • Giao tiếp bằng chuẩn I2C.
    • Dải quang phổ gần với tần số mắt người nhìn thấy.
    • Tín hiệu đầu ra là tín hiệu số.
    • Thang đo từ 1 – 65535 lux.
    • Mức độ tiêu thụ điện năng thấp.
    • Lọc nhiễu trong dải tần 50 – 60 Hz.
    • Mức logic giao tiếp có thể đến 1.8V.
    • Không cần các thiết bị bên ngoài để hỗ trợ chạy Ic như thạch anh …
    • Có thể tương thích với nhiều nguồn sáng như mặt trời, đèn led trắng, đèn halogen…
    • Có thể thay đổi địa chỉ giao tiếp(địa chỉ I2C).
    • Có thể config để đọc được giá trị nhỏ nhất là 0.23 lux.
    • Sai số nhỏ (20%).
    • Ảnh hưởng của tia hồng ngoại đến việc đo lường là nhỏ.

    Nếu bạn dùng module GY-30 BH1750 thì một số thông số đầu vào như sau:

    • VCC : chân cấp nguồn, điện áp đầu vào từ khoảng 3.3 -> 6VDC.
    • ADD: chân này là chân thay đổi địa chỉ nếu cần thiết, default nó sẽ là mức thấp: địa chỉ I2C sẽ là 0x23, nếu ở mức cao sẽ là 0x5C.
    • SCL : chân clock của giao tiếp I2C.
    • SDA: chân Data của giao tiếp I2C.
    • GND: chân nối mass của module.

    Một số command thông dụng khi giao tiếp với IC:

    • Power down(0x00) : Set IC ở chế độ không hoạt động.
    • Power on(0x01) : Set IC ở chế độ hoạt động.
    • Reset(0x07) : Reset giá trị các thanh ghi của IC. Command này không hoạt động khi IC ở mode Power down.
    • Continuously H-Resolution Mode(0x10): Cài đặt IC ở chế độ đo liên tục với độ phân giải là 1 lux. Thời gian đo cập nhật giá trị trung bình sẽ là 120ms.
    • Continuously H-Resolution Mode2(0x11): Cài đặt IC ở chế độ đo liên tục với độ phân giải là 0.5 lux. Thời gian đo cập nhật giá trị trung bình sẽ là 120ms.
    • Continuously L-Resolution Mode(0x13): Cài đặt IC ở chế độ đo liên tục với độ phân giải là 4 lux. Thời gian đo cập nhật giá trị trung bình sẽ là 16ms.
    • One Time H-Resolution Mode(0x20): Cài đặt IC ở chế độ đo 1 lần với độ phân giải là 0.5 lux, thời gian đo cập nhật giá trị trung bình sẽ là 120ms. Sau khi cập nhật giá trị IC sẽ chuyển sang power down, muốn đo lại thì chúng ta phải gửi command power on để tiếp tục.
    • One Time H-Resolution Mode2(0x21): Cài đặt IC ở chế độ đo 1 lần với độ phân giải là 0.5 lux, thời gian đo cập nhật giá trị trung bình sẽ là 120ms. Sau khi cập nhật giá trị IC sẽ chuyển sang power down, muốn đo lại thì chúng ta phải gửi command power on để tiếp tục.
    • One Time L-Resolution Mode(0x23): Cài đặt IC ở chế độ đo 1 lần với độ phân giải là 4 lux, thời gian đo cập nhật giá trị trung bình sẽ là 16ms. Sau khi cập nhật giá trị IC sẽ chuyển sang power down, muốn đo lại thì chúng ta phải gửi command power on để tiếp tục.
    • Change Measurement time(01000_MT[7,6,5], 011_MT[4,3,2,1,0]): Thay đổi độ phân giải trong quá trình đo lường, muốn tăng độ chính xác thì thời gian đo sẽ chậm hơn và ngược lại.

    Note : Nhà sản xuất khuyến cáo chúng ta nên sử dụng mode H-resolution Mode, Với những môi trường tối chúng ta có thể sử dụng H-resolution Mode2 thay cho H-resolution Mode hoặc có thể thay đổi độ phân giải để đo được các giá trị nhỏ hơn.

    Cách tính toán giá trị đo lường. Với H-resolution Mode và thanh ghi độ phân giải có giá trị mặc định.

    Output = Value_Read/1.2/Mode.

    • Output là giá trị của độ sáng đơn vị là lux.
    • Value_Read : là giá trị đọc ra từ command read, giá trị này có 16 bit.
    • 1.2 là hệ số mặc định trong datasheet.
    • Mode: với H-resolution Mode2 thì Mode = 0.5 còn H-resolution Mode thì Mode = 1.
  3. Code với MX cube.
  4. Lưu đồ giải thuật:

    Call function reset -> Set sensitive with default value(MTreg) -> Set mode sensor -> read and process data.

    Sơ đồ kết nối.

    1. Cấu hình dung Mx Cube:
      • Cấu hình xung clock:
      • Cấu hình chân debug.
      • Cấu hình I2C.
      • Cấu hình clock hệ thống.
      • Cấu hình và generate code.
    2. Modify code generate:
      • Copy file thư viện là bh1750.h và main.h từ thư mục download vào project mà các bạn vừa generate ra, tương tự với file bh1750.c và main.c. Link download mình sẽ để ở dưới.
      • Thêm file thư viện bh1750.c trước khi build.
      • Build code.
      • Download Firmware.
      • Debug to view change.
    3. Note:
      • Để debug, các bạn cần có mạnh nạp có chức năng debug và đã được cài driver để máy tính nhận được mạch nạp này.
      • Ở trên mình sử dụng MCU là STM32F103C8T6, khi sử dụng các loại MCU khác thì cần chú ý các define, import, các chân chức năng…
      • Chú ý chọn reset and run trong chế độ config mạch nạp + chọn đúng loại mạch nạp.
      • Ở đây mình chỉ hướng dẫn cách lấy data, tùy vào ứng dụng khác nhau mà các bạn có thể sử dụng linh hoạt.
      • Source code gốc mình lấy từ github và có chỉnh sửa. Link source code gốc : https://github.com/lamik/Light_Sensors_STM32.
      • Ở đây mình chỉ hướng dẫn một số bước để lấy thư viện và thực thi code, để hiểu rõ hơn về cảm biến và cách thức xử lí các bạn cần đọc hiểu datasheet đồng đời debug thêm trong code, chúc các bạn thành công. Nếu có thắc mắc gì các bạn cứ để comment mình sẽ trả lời nhanh nhất trong thời gian có thể.
  5. Một số link tham khảo.
    1. Một số link mua hàng các bạn có thể tham khảo.
    2. Link 1 Link 2 Link 3 Link 4
    3. Link download tài liệu.
    4. Link datasheet Link manual Link thư viện cảm biến

14. OPTION BYTES TRONG STM8S

OPTION BYTES TRONG STM8S.

14. OPTION BYTES TRONG STM8S.

  1. CƠ SỞ LÝ THUYẾT.
  2. Option byte trong STM8S003 phục vụ một số chức năng riêng biết được liệt kế như sau:

    • ROP(Memory Readout protection) : Mục đích của chức năng này là sẽ khóa code, không cho phép đọc ngược, bảo vệ chương trình tránh khỏi tình trạng copy source code cũng như flash đè code. Trong trường hợp đã write ROP option byte là ON thì chúng ta chỉ có thể write ROP off và flash đè code khác xuống MCU, không thể đọc lại được code(nhà sản xuất có cách nào chưa công bố thì mình không biết).
    • UBC[0:7] : Config size cho bootloader. Một số ứng dụng cần update Firmware theo version chúng ta sẽ cần viết bootloader và application cho nó, các bit này sẽ hữu dụng khi chuyển vector ngắt đến địa chỉ mà application bắt đầu cũng như bảo vệ code cho vùng bootloader. Phần config này sẽ hữu dụng khi chúng ta sử dụng STVD và có nhược điểm vùng nhớ application bắt đầu phải chẵn và chia hết cho 64(Không config linh động được địa chỉ bắt đầu của application). Trong IAR sẽ có một số cách để config bootloader mà k cần sử dụng đến option này, các bạn có thể tham khảo thêm với IAR ở đây : http://laptrinharmst.blogspot.com/2021/11/bai-15-bootloader-stm8s-tren-iar.html và file AN2659.
    • AFR[0:7]: Config cho Alternate function. Như các bạn đã biết mỗi chân vi điều khiển có thể có nhiều chức năng khác nhau,để linh hoạt trong việc config các chức năng này nhà sản xuất đã thêm tính năng để việc sử dụng chân điều khiển linh hoạt hơn. Ví dụ: Chân PC5 của STM8S003 có chức năng mặc định sẽ là SPI tạo xung clock, ngoài ra nó cũng là chân Timer2 chanel1, để sử dụng tính năng timer chúng ta bắt buộc phải write thêm bit config AFR0. Chức năng khác nhau của config này các bạn có thể tham khảo thêm trong datasheet.
    • HSITRIM : config độ phân giải cho bộ xung clock HIS.
    • LSI_EN : config cho phép bộ dao động LSI như là bộ cung cấp clock chính cho MCU.
    • IWDG_HW, WWDG_HW, WWDG_HALT : cho phép bộ independent watchdog, window watchdog hoạt động 1 cách tự động sau khi cấp nguồn hay không.
    • EXTCLK: cho phép sử dụng thạch anh ngoài hay không.
    • CKAWUSEL : config low-speed clock source cho bộ AWU(Analog wakeup) lấy từ LSI hay HSE.
    • PRSC : đi chung với config CKAWUSE, nếu lấy từ HSE thì tương ứng với tỷ lệ chia.
    • HSECNT[0:7] : config thời gian để bộ dao động ngoại được ổn định trước khi vận hành, option này sẽ sử dụng EXTCLK on.

    Về mặt lí thuyết chúng ta có thể nạp option byte mỗi lần flash code theo tool nạp tuy nhiên khi viết chương trình bootloader hoặc một số mục đích khác chúng ta có thể dùng các tập lệnh trong thư viện flash để ghi các option byte này mà k cần sử dụng tool nạp. Vùng nhớ của các option tương ứng với bảng bên dưới.

  3. Ví dụ với Option byte.
  4. Ví dụ: viết chương trình sử dụng TIM2_CH3 chớp tắt led với chu kì 1s,duty cycle là 50% trên chân PD2, sử dụng dụng tính năng ghi flash để ghi các byte option mà không cần dùng tool. Chân PD2 có chức năng TIM2_CH3, tuy nhiên nó là Aternate function, cần write option byte mới sử dụng được nếu không chỉ còn cách flash lại các option byte.

    1. Cấu hình bộ nhớ Flash.
    2. Chú ý việc cấu hình ở đây sẽ tương tự như việc cấu hình ghi vào EEPROM.

    3. Cấu hình bộ Timer 2.
    4. Ghi các option byte.
    5. Sử dụng STVP để nạp chương trình mà k cần ghi các option byte.
    6. Kết quả thu được sẽ là led trên chân PD2 sẽ chớp tắt với chu kì 1s(0.5s sáng và 0.5s tắt). Chúc các bạn thành công.

Link tải ví dụ với option bytes ở trên.

13. FLASH và EEPROM TRONG STM8S.

FLASH và EEPROM TRONG STM8S.

FLASH và EEPROM TRONG STM8S.

  1. Cơ Sở Lý Thuyết.
  2. Chào các bạn, Hôm nay mình sẽ tiếp tục một số tìm hiểu về Flash và EEPROM.Chúng là 2 vùng nhớ khác nhau trong STM8S, tuy nhiên về cấu tạo và bản chất thì tương đối giống nhau. Tổng quan về bộ nhớ của của STM8S.

    Bảng thống kê dưới đây sẽ so sánh một số thông tin chung giữa 2 loại:

    Bộ nhớ Flash sử dụng các cổng logic NAND nên giá thành sẽ rẻ hơn, tốc độ truy cập cũng sẽ chậm hơn, bộ nhớ Flash thường truy cập theo khối trong khi EEPROM thì là byte, chức năng tương ứng cũng khác nhau. Ở STM8S003 thì bộ nhớ Flash(8k byte) dùng để lưu trữ chương trình trong khi EEPROM(128 bytes) thì thường dùng để lưu một số thông tin không xóa sau khi Flash hoặc mất điện. Với những thông tin bạn không muốn mất sau khi Flash Firmware mới và tốc độ truy cập cao thì thường chúng ta sẽ sử dụng bộ nhớ EEPROM, ngược lại nhưng thông số thay đổi mỗi lần Flash, tốc độ truy cập thông thường và khối lượng data lớn thì chúng ta sẽ sử dụng bộ nhớ Flash.

  3. Ví dụ với bộ nhớ Flash.
  4. Ví dụ: Ghi data vào 16 byte cuối cùng của bộ nhớ Flash với địa chỉ 0x9FF0 -> 0x9FFF data tương ứng từ 0 -> 15, Sau khi đọc lại data đã ghi, nếu đúng đèn led trên chân PD3 sẽ sáng, ngược lại nếu ghi bị failed hoặc read bị failed thì đèn ở chân PD3 sẽ tắt.

    Cách thức kiểm tra: các bạn sẽ dùng mạch nạp stlink_v2 + phần mềm “ST Visual Programmer” để đọc lại toàn bộ vùng nhớ và kiểm tra data thuộc địa chỉ từ 0x9FF0 -> 0x9FFF.

    1. Config bộ nhớ Flash.
    2. Trước khi thực hiện đọc ghi vào vùng nhớ Flash, chúng ta cần thực hiện một số config quan trọng như: Deinit lại toàn bộ vùng nhớ, Cài đặt thời gian xử lí, đồng thời mở khóa vùng nhớ. “FLASH_MEMTYPE_PROG” tương ứng với việc chọn vùng nhớ Flash để giao tiếp.

    3. Thực thi code giao tiếp với bộ nhớ Flash
    4. Trước tiên chúng ta sẽ ghi data với giá trị từ 0 -> 15 vào địa chỉ bắt đầu từ 0x9FF0 -> 0x9FFF(16 bytes). Đợi 1 khoảng thời gian nhỏ để chắc chắn rằng việc ghi đã thực thi xong, tiếp đến chúng ta sẽ đọc lại và kiểm tra vùng nhớ đã ghi, nếu chỉ cần 1 địa chỉ sai thì sẽ thoát quá trình đọc. Nếu kết quả ghi vào đọc lại giống nhau thì đèn led trên chân PD3 sẽ sang, ngược lại thì tắt.

      Chú ý: Để thao tác với vùng nhớ Flash thì chúng ta cần chú ý rằng code của quá trình biên dịch k được tràn vào vùng nhớ cần đọc/ghi. Ngoài lệnh đọc/ghi thông thường chúng ta có thể sử dụng đọc/ghi các block(IN_RAM trong thư viện) để với mục đích nâng cao tốc độ tương tác khi thao tác với số lượng data lớn.

    5. Kết quả thực thi.
    6. Sau khi dùng stlink_V2 và phần mềm “ST Visual Programmer” để đọc lại toàn bộ vùng nhớ, kết quả sẽ như hình bên dưới.

  5. Ví dụ với bộ nhớ EEPROM.
  6. Ví dụ: ghi data vào 16 byte cuối cùng của bộ nhớ Flash với địa chỉ 0x4000 -> 0x400F data tương ứng từ 0 -> 15, Sau khi đọc lại data đã ghi, nếu đúng đèn led trên chân PD3 sẽ sáng, ngược lại nếu ghi bị failed hoặc read bị failed thì đèn ở chân PD3 sẽ tắt. Cách thức kiểm tra: các bạn sẽ dùng mạch nạp stlink_v2 + phần mềm “ST Visual Programmer” để đọc lại toàn bộ vùng nhớ và kiểm tra data thuộc địa chỉ từ 0x4000 -> 0x400F.

    Tương tự như bộ nhớ Flash, giao tiếp với EEPROM cũng tương tự, chỉ khác cấu hình và địa chỉ.

    1. Config bộ nhớ EEPROM.
    2. Thực thi code giao tiếp với bộ nhớ Flash.
    3. Kết quả.
    4. Note : ngoài lệnh Read/Write , chúng ta còn một số lệnh như xóa, ghi 1 word… Các bạn có thể tham khảo trong file stm8s_flash.c và áp dụng thử cho project của mình. Bộ nhớ EEPROM của STM8S003 chỉ là 128 bytes tức là bắt đầu từ 0x4000 ->0x407F.

Link tải ví dụ với bộ nhớ flash. Link tải ví dụ giao tiếp với EEPROM

Bài 15: Bootloader STM8S với IAR.

Bài 15: Bootloader STM8S với IAR.

Bài 15: Bootloader STM8S với IAR.

Chào các bạn, hôm nay mình sẽ hướng dẫn các bạn một số bước và lưu ý để viết chương trình code bootloader và application cho STM8S.

  1. Bootloader và Application là gì.
  2. Để hiểu về bootloader, trước tiên bạn cần hiểu thứ tự thực thi code và vùng nhớ của vi điều khiển, ở đây là STM8S003F3P6. Với MCU này thì bộ nhớ Flash(bộ nhớ lưu trữ code) sẽ là 8Kbyte, và địa chỉ lưu code sẽ là từ 0x00 8000 đến 0x00 9FFF. Chương trình cũng sẽ load từ địa chỉ 0x00 8000 đến 0x00 9FFF và khi bị reset thì MCU cũng sẽ load chương trình theo thứ tự này.

    Bootloader là một ứng dụng được lập trình sẵn dụng để cập nhật Firmware cho các MCU mà không cần tới mạch nạp. Bootloader sử dụng một trong các chuẩn truyền thông có sẵn(One wire, UART, USB, SPI, CAN, I2C …) để cập nhật lại bộ nhớ flash giúp thực thi các ứng dụng một cách linh hoạt hơn. Bootloader và Application thường sử dụng cho các sản phẩm có phần giao tiếp như Bluetooth, wifi, usb, Rs232, zigbee, rs232… Ví dụ : bạn muốn cập nhật Firmware từ xa cho một sản phẩm mà không cần tháo dỡ phần cứng hoặc không cần đến tận nơi có phần cứng đó.

    • Bootloader là phần code được viết sẵn và nạp trong một vùng nhớ flash cố định, code này hầu như không thay đổi và hoạt động phải ổn định(bạn cứ tưởng tượng bootloader cho một sản phẩm đã bán đến khách hàng mà update FW bị lỗi và phải thu hồi về để nạp lại bootloader thì hơi chuối…).Code này thường chiếm ít dung lượng của bộ nhớ vì mục đích của nó chỉ dung để cập nhật Firmware và cung cấp một số ít thông tin cần thiết. phần code này thường được nạp bằng mạch nạp(debugger) và nạp một lần duy nhất trước khi Release.
    • Application Firmware là phần code Firmware sẽ thường xuyên thay đổi, ví dụ sản phẩm có tính năng A, người dùng muốn thêm tính năng B, giả sử phần cứng của bạn đã hỗ trợ tính năng B, bạn chỉ cần viết thêm phần code của tính năng B và update lại Application FW thông qua phần code Bootloader.

    Tùy thuộc từng dự án và mục đích sử dụng bộ nhớ flash sẽ chia làm nhiều phần khác nhau. Ở đây, mình ví dụ STM8S003F3P6 sẽ chia code bootloader là 2kbyte, và application sẽ là 5.75kbyte, config sẽ là 0.25kbyte. Thì sơ đồ vùng nhớ flash sẽ như sau:

    • Bootloader : phần này sẽ chứa code của bootloader, mục đích chính để update FW, code build cho phần phải nhỏ hơn 2 kbyte. Tùy thuộc vào khả năng viết code và ứng dụng nó sẽ có dung lượng khác nhau, size code của phần này càng nhỏ càng tốt, để tiết kiệm vùng nhớ cho Application.
    • Aplication : vùng nhớ này sẽ chứa code thay đổi theo từng version và chiếm dung lượng lớn nhất. Size của code buid ra không được vượt quá dung lượng quy định là 5.75 kbyte.
    • Config : vùng này sẽ chứa thông số config như version bootloader, phần bảo mật để cho phép upload code khi có yêu cầu, các thông số hoạt động cần thiết cho bootloader…

    Lưu đồ giải thuật của việc sử dụng bootloader và application như sau :

  3. Một số điểm lưu ý khi viết chương trình bootloader và application.
  4. Ở đây mình viết bootloader và application bằng IAR cho STM8, một số lưu ý khi viết chương trình như sau:

    1. Làm sao để nhảy từ vùng nhớ application sang bootloader và ngược lại.
      • Nhảy tới vùng nhớ application từ code bootloader : Chúng ta sẽ sử dụng ngôn ngữ máy để nhảy tới địa chỉ mong muốn, ở đây vùng nhớ application của mình bắt đầu từ 0x00 8800(tương ứng bootloader từ 0x00 8000 -> 0x00 87FF = 2Kbyte). Lệnh để nhảy tới tương ứng là asm("JPF $8800").
      • Nhảy tới vùng nhớ bootloader từ application: Vùng nhớ bootloader được quy định bắt đầu từ 0x00 8000 nên việc nhảy tới vùng nhớ này tương ứng với việc reset MCU(thường là soft reset). Có nhiều cách để reset MCU, ở đây mình dùng cho phép Independent watchdog(IWDG) hoạt động và chờ cho đến khi bộ IWDG tràn, lúc này MCU sẽ được reset. Cú pháp như sau:
      • IWDG->KR = IWDG_KEY_ENABLE; while (1); // Wait until reset occurs from IWDG

    2. Chuyển đổi các vector ngắt khi chương trình thực thi ở vùng nhớ application.
    3. Địa chỉ các vector ngắt mặc định bắt đầu từ 0x82000000, khi chuyển sang vùng nhớ application chúng ta cũng phải chuyển đổi vector ngắt để khi nhảy tới vùng nhớ application ngắt vẫn thực thi bình thường và không còn thực thi ở vùng nhớ bootloader. Mình có search việc thực thi này và tham khảo một số page khác. Vector ngắt của mình sẽ bắt đầu địa chỉ 0x82008800. Việc config sẽ thực thi ở code bootloader và khai báo như sau:

      __root const long reintvec[]@".intvec"= { 0x82008080,0x82008804,0x82008808,0x8200880c, 0x82008810,0x82008814,0x82008818,0x8200881c, 0x82008820,0x82008824,0x82008828,0x8200882c, 0x82008830,0x82008834,0x82008838,0x8200883c, 0x82008840,0x82008844,0x82008848,0x8200884c, 0x82008850,0x82008854,0x82008858,0x8200885c, 0x82008860,0x82008864,0x82008868,0x8200886c, 0x82008870,0x82008874,0x82008878,0x8200887c, };

    4. Cấu hình IDE để thay đổi địa chỉ bắt đầu build khác địa chỉ mặc địnhs 0x00 8000.
    5. Trong config của iar có thể thay đổi địa chỉ build bắt đầu việc load file .icf, file này có chức năng cấu hình vùng nhớ, eeprom, stack heap size…. File mặc định nếu chưa cấu hình gì sẽ nằm trong thư mục cài đăt iar. Ở trên máy của mình sẽ là C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.0\stm8\config\lnkstm8s003f3.icf với MCU sử dụng là STM8S003F3P6.

      Việc đổi địa chỉ tiến hành như sau: copy file .icf tương ứng với project bạn sử dụng vào trong thư mục chứa project, sửa địa chỉ mong muốn rồi lưu lại.

      Vào config project và chỉnh sửa lại link đến file .icf vừa thêm.

    6. Tăng tốc độ xóa và ghi trong bộ nhớ flash.
    7. Bình thường chúng ta sẽ sử dụng các function có sẵn trong thư viện “stm8s_flash” để thao tác với bộ nhớ flash, tuy nhiên tốc độ thực thi của chúng khá chậm, nhà sản xuất của đã hỗ trợ một số function khác dùng RAM để thực thi(chứa IN_RAM ở đầu function), tốc độ này nhanh hơn nhiều lần so với các function thông thường, tuy nhiên nó sẽ tiêu tốn RAM của vi điều khiển. Nếu sử dụng không tốt có thể dẫn tới treo vi điều khiển. Các function thao tác với flash cũng nằm trong file thư viện “stm8s_flash”. Để sử dụng tính năng này chúng ta phải define trong chương trình, bạn có thể sử dụng 1 trong 2 cách sau:

      • Define trực tiếp trong thẻ config:
      • Hoặc bỏ command trong file stm8s.h.
    8. Tối ưu code để code bootloader chiếm dung lượng nhỏ nhất.
      • Tối ưu thuật toán, biến để giảm dung lượng code nhỏ nhất.
      • Ví dụ: Các biến toàn cục có giá trị tối đa là 255 thì chỉ nên sử dụng uint8_t không nên sử dụng uint16_t hay uint32_t.

      • Sử dụng thanh ghi thay thế cho các function viết sẵn: Bạn có thể xem chi tiết các function, xóa bỏ các define kiểm tra tính safety code, sử dụng các thanh ghi trong chính function con để giảm size code. Chúng ta chỉ nên modify các function này khi cần tối ưu code flash, nếu còn nhiều bộ nhớ thì không nên modify function của nhà sản xuất vì nó sẽ giảm độ an toàn cũng như hiệu năng của code.
      • Ví dụ: Một function Init_GPIO sẽ có chi tiết các code như sau:

        Khi các bạn đã xác định rõ chân GPIO là chân input/output, interrupt/none interrupt, pull up/push pull thì không cần if else và bỏ đi đoạn check safety code. Code được viết lại như sau :

      • Tối ưu phép tính toán xor, or, and … với các giá trị tương đồng.
      • Ví dụ: Các phép toán or với giá trị 0 thì nên được xóa đi ví dụ: CLK->CKDIVR |= (uint8_t)CLK_PRESCALER_HSIDIV1; với define CLK_PRESCALER_HSIDIV1 = (uint8_t)0x00. Phép tính sẽ là CLK->CKDIVR |= 0x00; -> giá trị thanh ghi này không đổi -> chúng ta sẽ command luôn phép tính này để không tốn bộ nhớ cho phép tính này: //CLK->CKDIVR |= (uint8_t)CLK_PRESCALER_HSIDIV1;

  5. Demo chạy thử.
    1. Ở đây mình dùng Visual studio viết 1 tool update Firmware từ máy tính thông qua module UART USB. Các file cần chuẩn bị như sau:

      • 1 tool update dùng để chạy trên máy tính.
      • 1 file bootloader.
      • 2 file application chứa 2 version khác nhau và tốc độ thực thi led trên chân PD2 lần lượt là 500ms và 2000ms.
      • 1 module STM8S003F3P6, 1 module UART-USB, 1 mạch nạp stlink_v2.
    2. B1. Nạp file code bootloader thông ST visual programmer bằng mạch nạp stlink.
    3. Lưu ý: các bạn cần config và chọn đúng mạch nạp trước khi nạp bootloader.

    4. B1. Nạp file code bootloader thông ST visual programmer bằng mạch nạp stlink.
    5. B2. Kết nối board với máy tính thông qua module USB_UART.
    6. B3. Mở tool và chọn cổng UART mà máy tính đã nhận.
    7. B4.Chọn đến file hex application với thời gian nháy led là 100ms và version là 1.0 và nhấn nút Upgrade_8s.
    8. Sau khi update xong các bạn đọc version là 1.0 và quan sát led ở chân PD2 sẽ đổi trạng thái với thời gian là 100ms.

    9. B5. Chọn 1 file application khác với thời gian nháy led là 2000ms và version là 1.2. Kết quả sau khi update là:
    10. Note: Vì tính bảo mật và là thành quả của việc nghiên cứu nên mình sẽ không update source code như các hướng dẫn trước mong các bạn thông cảm. Bạn nào trong quá trình làm gặp khó khăn gì cứ comment hay inbox mình, mình sẵn lòng hỗ trợ trong thời gian ngắn nhất có thể. Bài viết có thể có một số thông tin chưa đúng, mong nhận đươc sự góp ý của các bạn. Chúc các bạn thành công!!!