Maix Bit (K210) Nanny Level Getting Started Tutorial---Basic Use of Peripherals

Maix Bit (K210) Nanny Level Getting Started Tutorial Series

Maix Bit (K210) Nanny Level Getting Started Tutorial—Environment Construction

Maix Bit (K210) Nanny Level Getting Started Tutorial - Cloud Training of Self-Training Model


这是K210快速上手系列文章,主要内容是,介绍K210的基本外设的使用、通过简单介绍一两个基本的硬件使用来掌握K210的外设开发(K210GPIO使用教程、K210串口使用教程)

The prerequisite for reading this article: the reader has basic hardware knowledge, and has been exposed to similar STM32, C51, Arduino, etc. If you haven't touched similar hardware, this article may not be suitable for readers.


1. Basic introduction of K210 hardware

Maix py on-chip peripherals support GPIO, I2C, PWM, I2S, SPI, UART, TIMER, WDT, network, etc. (Maix py is just a project, transplanted to K210, its function is to support python development, but the hardware used is K210).

K210 uses FPIOA (Field Programmable IO Array, Field Programmable Input and Output Array) technology, through which the pins can be set to the above functions at will. As shown in the figure below, pin 1 can be set as (mapping) GPIO, or as (mapping) UART, or as (mapping) PWM. Since the hardware is limited , it cannot be set to the same hardware at the same time. For example, if there are three GPIOs, pin 1 uses GPIO1, but pin 2 cannot use GPIO1.

Simplified illustration:insert image description here

This is different from the one of the single-chip microcomputer . The function of a certain pin of the single-chip microcomputer has been fixed when the chip is designed , and can only be set as a fixed function. For example, a pin of STM32 has been set to have the function of serial port transmission. In addition to the basic GPIO functions (every pin has), the function of this pin is only the function of serial port transmission.

We already know that any pin can be set (mapped) as GPIO, UART and other functions, so what functions can be set? What pins are already used for some function? You can see the official peripheral list , and I will briefly introduce the functions below.

It can be mapped to: JTAG, SPI0, UARTHS, RESV6, CLK_SP, GPIOHS, GPIO, UART, SPI, I2S, CMOS, TIMER. For details, please refer to the peripheral table on the official website.

The following GPIOHS has been used, that is, GPIOHS4/5/27/28/29 try not to use these functions.

GPIOHS Function describe
GPIOHS5 LCD_DC LCD read and write signal pins
GPIOHS4 LCD_RST LCD reset chip pin
GPIOHS29 SD_CS SD card SPI chip select
GPIOHS28 MIC_LED_CLK SK9822_DAT
GPIOHS27 MIC_LED_DATA SK9822_CLK

If the SD card, sensor, LCD, and REPL functions are used, attention should be paid to the following peripheral functions and pins used below.

use to equipment Peripheral function use pin
SD SPI1_SCLK/SPI1_D0/SPI1_D1/GPIOHS29/SPI0_SS1 PIN25/PIN26/PIN27/PIN28/PIN29
LCD SPI0_SS3/SPI0_SCLK/GPIOHS30/GPIOHS31 PIN36/PIN37/PIN38/PIN39
sensor SCCB_SDA/SCCB_SCLK/CMOS_RST/CMOS_VSYNC/CMOS_PWDN/CMOS_HREF/CMOS_XCLK/CMOS_PCLK PIN40/PIN41/PIN42/PIN43/PIN44/PIN45/PIN46/PIN47
REPL UARTHS_RX/UARTHS_TX PIN4/PIN5

基本引出引脚资源图, this picture comes from the official document
insert image description here

2. Simple tutorial on GPIO usage

1. Prerequisites for using GPIO

a:FPIOA

As mentioned above, we can set the function of the pin at will, and we can set the pin mapping through the FPIOA module.

Set the peripheral function corresponding to the pin

set_function(pin, func)

pin: pin number, value [0, 47], see Maix bit data download for details : including the schematic diagram and some pins that have been used above
func: see the official peripheral function settings for details of the functions here

the code

from Maix import FPIOA # FPIOA模块
from fpioa_manager import fm # 注册芯片内部功能和引脚
LED_G=14
fpioa = FPIOA() #设置类
fpioa.set_function(LED_G, fm.fpioa.GPIOHS0) #设置引脚14为高速GPIO模式

b:fpioa_manager

在Maix py中,我们通常不直接使用fpioa.set_function去设置引脚的功能,而是使用register(pin, func, force)这个函数来控制引脚分配

The function of FPIOA has been briefly understood above, but there is a simple module that can help us manage FPIOA, this is the above fmmodule.

Function: Pin Mapping

register(pin, func, force)

Function: Map the pin on the pin to a certain function
Parameter introduction:

  • pin: function mapping pin
  • function : set the function of the peripheral
  • force: Mandatory allocation, if it is True, you can register for the same pin multiple times; False does not allow multiple registrations for the same pin.

The pin here, the official document does not say whether it takes the value [0, 47] , but I guess it should be (refer to the routine used by the official set_function and the routine used by register, the value of the pin is the same), and this fmmodule It is for managing fpioa itself, so only the function of fpioa should be used.

The parameters in function and set_function are the same here. That is to say, the functions of set_function and register are similar , and the first two parameters are also the same.


Function: Pin Release

unregister(pin)

Function: Release the function bound on the pin
Parameters:

  • pin,[0,47]

Return value: None

simple code

from fpioa_manager import fm
LED_G=14
fm.register(LED_G, fm.fpioa.GPIO0, force=True)#强制设置某个Pin14为GPIO0
fm.unregister(LED_G)#释放pin14绑定的GPIO0的功能

For more specific functions, see the official documentation

2. Use of GPIO peripherals

a: Preliminary study on GPIO

GPIO is a class, we usually operate this class to set GPIO, high-speed GPIO is the same

Function: apply for a GPIO class

class GPIO(ID, MODE, PULL, VALUE)

Function: Register a GPIO class
Parameters:

  • GPIO ID: GPIOx, GPIOHSx, which GPIO to choose
  • MODE: GPIO mode, input/output, GPIO.IN/GPIO.OUT
  • PULL: GPIO pull-down mode, up/down/no setting mode, GPIO.PULL_UP/GPIO.PULL_DOWN/GPIO.PULL_NONE
  • VALUE: set GPIO state

Return value: None


Function: Set GPIO status

GPIO.value([value])

Function: Set GPIO status
Parameters: value can be set to 1 (high level)/0 (low level)
Return value: If the value is empty, return the current GPIO status

了解完基本的两个GPIO设置就可以点亮小灯了
Let's look at the schematic and see which pin the LED is connected to
insert image description here
insert image description here

From the schematic diagram, we can know: LED_B is connected to IO14, LED_R is connected to IO13, LED_G is connected to IO12, and we can know that the small light is on when the IO output is low .

Simple routine:

import utime #与系统时间有关模块
from Maix import GPIO #导入GPIO模块
from fpioa_manager import fm #导入管理FPIOA模块

# 效果,每隔1S亮灭 蓝灯

times=10 #亮灭10次
LED_B=14 #蓝灯IO定义

fm.register(LED_B,fm.fpioa.GPIO0) #注册引脚为GPIO0功能

led_r=GPIO(GPIO.GPIO0,GPIO.OUT)#操作设置GPIO模式

while times:
    utime.sleep_ms(500) #系统休眠0.5s
    led_r.value(0) #点亮
    utime.sleep_ms(500)
    led_r.value(1) #熄灭
    times=times-1
del led_r    # 释放类
fm.unregister(LED_B) #释放LED_B绑定的GPIO0

Put it directly on the IDE and you can run it directly~
insert image description here
The running effect is as follows: the blue light is cycled
insert image description here

b: GPIO simple advanced

Here is a brief introduction to GPIO advanced to trigger GPIO through interrupts , excluding the function of GPIO wake-up (Maix Py does not seem to support it), and only GPIOHSsupports interrupt triggering.

Function: GPIO interrupt setting

GPIO.irq(CALLBACK_FUNC,TRIGGER_CONDITION,GPIO.WAKEUP_NOT_SUPPORT,PRORITY)

Function: Set GPIO interrupt
Parameter introduction:

  • CALLBACK_FUNC: Callback function, pay attention to support K210 supports 7 interrupts, and share one interrupt manager, that is, the set interrupts all trigger the same interrupt function. You can check which GPIO reads the interrupt in the interrupt callback function, see the following routine for details .
  • TRIGGER_CONDITION: trigger mode. There are rising edge triggers/falling edge triggers/both rising and falling edge triggers, GPIO.IRQ_RISING/GPIO.IRQ_FALLING/GPIO.IRQ_BOTH
  • PRORITY: It is the interrupt priority, which can be set from 1 to 7.
    Return value: None

Function:
GPIO close interrupt setting

GPIO.disirq()

Return value: None
Simple usage routine:

import utime
from Maix import GPIO
from fpioa_manager import fm

LED_B=14 #蓝灯IO定义
KEY=16 #开发板上RST的按键IO
times=10

led_status=0
def test_irq(pin_num):
    print(pin_num) # pin_num GPIO 类,不是常规的Pin类
    if pin_num==GPIO(0): # 判断不同GPIO 控制中断输入
        global led_r
        global led_status
        if led_r.value()==0: # 读取LED引脚电平状态
            led_r.value(1)
        else:
            led_r.value(0)
        
fm.register(LED_B,fm.fpioa.GPIO0) #注册引脚为GPIO0功能
    
led_r=GPIO(GPIO.GPIO0,GPIO.OUT)#操作设置GPIO模式

fm.register(KEY, fm.fpioa.GPIOHS0)
key = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_NONE)
key.irq(test_irq, GPIO.IRQ_RISING, GPIO.WAKEUP_NOT_SUPPORT,1)
#print("Gpio irq test")
while times:
    utime.sleep_ms(1000) # 在 3 秒内等待触发
    times=times-1
key.disirq() # 禁用中断
fm.unregister(KEY)


运行效果: Click RST on the development board, the state of the small light changes

The complaint is really that I have taken the official Sipeed documentation, which is incomplete, and only part of it. For some functions, you have to read the chip manual and the official K210 programming manual by yourself.


3. UART simple tutorial

After understanding the use process of UART, that is, pin mapping, and using related classes to control the state of UART, UART first introduces a board_info, a user-level panel-level configuration module.

1. Understand board_info

The role of this board_info is to help us manage pins, such as which pin is used and what function is used, which can be set and viewed.

Before understanding board_info, you must first download and configure board_info , which is already configured in the firmware, and the unmodified code is as follows. This is a text written using javascript objects. The core is the content of config. We first see the board_info in config. This is what we want to set, and the rest do not need to be changed.
Here config means:
the config object contains two keys, type and board_info, value, type is a string type, board_info is an object type, and the attributes of the board_info object are all plastic

import json 

config = {
    
    
  "type": "bit",
  "board_info": {
    
    
      'BOOT_KEY': 16,
      'LED_R': 13,
      'LED_G': 12,
      'LED_B': 14,
      'MIC0_WS': 19,
      'MIC0_DATA': 20,
      'MIC0_BCK': 18,
  }
}

cfg = json.dumps(config)
print(cfg)

try:
  with open('/flash/config.json', 'rb') as f:
    tmp = json.loads(f.read())
    print(tmp)
    if tmp["type"] != config["type"]:
      raise Exception('config.json no exist')
except Exception as e:
  with open('/flash/config.json', "w") as f:
    f.write(cfg)
  import machine
  machine.reset()

Look at the code running results to simply understand the function of the module:

from board import board_info 
print(board_info.LED_R)
print(board_info.LED_B)
print(board_info.LED_G)

Output numbers: 14, 13, 12
insert image description here
From the output results, simply look at the source code, which means to connect LED_R to 14, the effect is similar to LED_R=14

2. Simply modify board_info

Here simply modify the board_info first, and set the UART to send and receive.

import json 

config = {
    
    
  "type": "bit",
  "board_info": {
    
    
      'BOOT_KEY': 16,
      'LED_R': 13,
      'LED_G': 12,
      'LED_B': 14,
      'UART_TX': 1,
      'UART_RX': 2,      
      'MIC0_WS': 19,
      'MIC0_DATA': 20,
      'MIC0_BCK': 18,
  }
}

cfg = json.dumps(config)
print(cfg)

try:
    with open('/flash/config.json', 'rb') as f:
        tmp = json.loads(f.read())
        print(tmp)
        if tmp["type"] != config["type"]:
            raise Exception('config.json no exist')
except Exception as e:
    with open('/flash/config.json', "w") as f:
        f.write(cfg)
import machine
machine.reset()

Copy the file directly to the IDE and run it, the IDE will modify the configuration file (permanent) in /flash/config.json, and then we will run it to see the effect

insert image description here
In fact, the code running github cannot be modified. Viewing the content through mpfs has not been written in, and the printed information is still the default information. But it can be modified on the sd card, which proves that the code is correct, it should be flashprotected by something, and the permissions are not enough .

mpfs [/sd]> cat /flash/config.json
{
    
    
    "board_info": 
    {
    
    
        "LED_B": 14, 
        "MIC0_DATA": 20, 
        "LED_G": 12,
        "MIC0_BCK": 18, 
        "BOOT_KEY": 16, 
        "LED_R": 13, 
        "MIC0_WS": 19,
        "UART_TX": 1,
        "UART_RX": 2
    
    }, "type": "bit"
}

I pulled the file to the PC, modified and wrote the content of the following jsscript file, then deleted /flash/cofig.json, and re-uploaded the modified /flash/cofig.json file, here use mpfs file to transfer the file , of course IDE is also possible. If you don't understand, click here to include the basic installation and use of mpfs

In fact, the contents of the modified cofig.json look like this

{
    
    
    "board_info": 
    {
    
    
        "LED_B": 14, 
        "MIC0_DATA": 20, 
        "LED_G": 12,
        "MIC0_BCK": 18, 
        "BOOT_KEY": 16, 
        "LED_R": 13, 
        "MIC0_WS": 19,
        "UART_TX": 1,
        "UART_RX": 2
    
    }, "type": "bit"
}

After the replacement, the display will be normal.

mpfs [/flash]> cat config.json
{
    
    
"board_info": 
	{
    
    
	 "MIC0_DATA": 20,
	 "MIC0_BCK": 18,
	  "LED_B": 14, 
	  "MIC0_WS": 19, 
	  "LED_R": 13, 
	  "UART_TX": 1, 
	  "BOOT_KEY": 16, 
	  "LED_G": 12, 
	  "UART_RX": 2
	  }, 
	  "type": "bit"
}

The correct value is obtained through the following code test:

from board import board_info

print("\nboard_info.UART_TX is",board_info.UART_TX)
print("board_info.UART_TX is",board_info.UART_RX)

insert image description here

特别注意, if you use the board_info module, the config.json file may not be modified, and you need to manually replace the file content by yourself . There are generally two replacement methods, one is to directly modify the content of the source file on the PC, and then pull it into Maix Bit. The other is to write out of the flash, such as an SD card, and then move the files in the SD card to the flash

3. Machine module introduction

The machine module is a library for running and operating the hardware on the K210. This library supports access to PWM, I2S, SPI, UART, Timer, WDT, and network.

However, according to the routines, it is convenient to operate the hardware through this library, but it is not as flexible as a single-chip microcomputer. There are advantages and disadvantages.

Introduction to commonly used machine functions:

machine.reset()

Function: reset device, similar to restart function

Constructor:

machine.xxx(),xxx可以为PWM、I2S、SPI、UART、Timer、WDT

For example:

from machine import WDT
wdt0 = WDT(id=1, timeout=4000, callback=on_wdt, context={
    
    }) # 申请一个看门狗类

from machine import UART
uart = UART(uart,baudrate,bits,parity,stop,timeout, read_buf_len) # 申请一个串口类


4. Basic use of UART

Here we just use the USB-to-serial port module to connect the PC and Maix bit through the serial port, and use the previously configured config.json file.

If the serial port cannot be recognized, after connecting the cable, it is found that the serial port cannot be recognized, it may be that the driver is not installed properly, check what chip your USB-to-serial port module uses, and then install the corresponding driver, such as CH340/CH341.

a: Introduction to basic functions

Function: serial port construction

UART(uart,baudrate,bits,parity,stop,timeout, read_buf_len)

Function: apply for a UART
parameter introduction:

  • uart: serial port number, UART.UART1, UART.UART2, etc.,
    see the official appendix for details on what peripherals can be used
  • bits: UART data width, support 5/6/7/8 (the default serial port (UARTHS) used by REPL only supports 8-bit mode), default 8
  • parity: parity bit, support
    None, machine.UART.PARITY_ODD, machine.UART.PARITY_EVEN (the default
    serial port (UARTHS) used by REPL only supports None), default None
  • stop: stop bit, support 1, 1.5, 2, default 1
  • timeout: serial port receive timeout
  • read_buf_len: Serial port receiving buffer, the serial port 中断receives data through the serial port, if the buffer is full, it will automatically stop data receiving

Return value: None


Function: read serial port buffer data

uart.read(num)

Function: read serial port buffer data
Parameters:

  • num is the read size, unit bype

Return value: return the read content, the type is bype


Function: serial port write data

uart.write(buf)

parameter:

  • buf is the content written to the serial port
    Return value: the amount of data written

Function: logout serial port

uart.deinit()

Parameters: None
Return Value: None

b: Simple serial port sending and receiving code

from machine import UART
from board import board_info
from fpioa_manager import fm

# 收发次数
rece_time = 3

# 引脚映射
fm.register(board_info.UART_TX, fm.fpioa.UART1_TX, force=True) # UART_TX是PIN1
fm.register(board_info.UART_RX, fm.fpioa.UART1_RX, force=True) # UART_RX是PIN2


uart_1 = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096) # 申请串口
print("UART TX/RX TEST ON")                                                                                                                                                                                                                                                                          
while rece_time:
    read_data=uart_1.read()
    if read_data:# 判断是否读取到数据
        read_str = read_data.decode('utf-8')
        uart_1.write(read_str+"\n")# 将读取到的数据+\n发送到上位机
        rece_time=rece_time-1
print("UART TX/RX TEST OFF")
uart_1.deinit()
del uart_1

operation result:
insert image description here

b: serial port send and receive code control LED

Since it involves data sending and receiving and processing, two versions are provided here, one is a simple single-threaded mode and the other is a multi-threaded mode. According to the documentation, the _thread module is not stable, and Maix py does not support threading.

单线程模式: The upper computer inputs LED ON to turn on the LED, and inputs LED OFF to turn off the LED

from machine import UART
from Maix import GPIO 
from board import board_info
from fpioa_manager import fm

# 引脚映射
fm.register(board_info.UART_TX, fm.fpioa.UART1_TX, force=True) # UART_TX是PIN1
fm.register(board_info.UART_RX, fm.fpioa.UART1_RX, force=True) # UART_RX是PIN2
fm.register(board_info.LED_B,fm.fpioa.GPIO0)                   

led_r=GPIO(GPIO.GPIO0,GPIO.OUT)#操作设置GPIO模式

uart_1 = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096) # 申请串口
print("UART TX/RX TEST ON")                                                                                                                                                                                                                                                                          
while 1:
    read_data=uart_1.read()
    if read_data:# 判断是否读取到数据
        read_str = read_data.decode('utf-8')
        if read_str=="LED ON":
            led_r.value(0) #点亮
            uart_1.write("LED ON\n")
        elif read_str=="LED OFF":
            led_r.value(1) #熄灭
            uart_1.write("LED OFF\n")
        elif read_str=="quit" or read_str=="exit":
            uart_1.write("quit the test\n")
        else:
            uart_1.write("input data error please inpue LED ON or LED OFF\n")
print("UART TX/RX TEST OFF")
fm.unregister(LED_B) #释放LED_B绑定的GPIO0

uart_1.deinit()
del uart_1
del led_r   

This is the result of the operation. This is the simplest way to control the hardware with instructions. The principle of communication between the K210 and other microcontrollers is the same afterward. Just configure the serial port.
insert image description here

多线程: The idea written below can be simply seen, but the code cannot be modified because the library does not support threading

from machine import UART
from Maix import GPIO 
from board import board_info
from fpioa_manager import fm

import threading


read_str=""
class led_thread (threading.Thread):
    def __init__(self, threadID, name):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
    
    def run(self,led_r,uart_1):
        with condLock:   # 条件锁 自动上锁
            condLock.wait()  # 暂停线程运行、等待唤醒
            global read_str # 共享数据区
            read_str = read_data.decode('utf-8')
            if read_str=="LED ON":
                led_r.value(0) #点亮
                uart_1.write("LED ON\n")
            elif read_str=="LED OFF":
                led_r.value(1) #熄灭
                uart_1.write("LED OFF\n")
            elif read_str=="quit" or read_str=="exit":
                uart_1.write("quit the test\n")
            else:
                uart_1.write("input data error please inpue LED ON or LED OFF\n")
             

class uart_thread (threading.Thread):
    def __init__(self, threadID, name):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = delay
    def run(self,uart_1):
        with condLock:   # 条件锁 自动上锁
            global read_str # 共享数据区
            read_data=uart_1.read()
            if read_data:# 判断是否读取到数据
                read_str = read_data.decode('utf-8')
                condLock.notify()  # 放行
         

if __name__ == "__main__":
    # 引脚映射
    fm.register(board_info.UART_TX, fm.fpioa.UART1_TX, force=True) # UART_TX是PIN1
    fm.register(board_info.UART_RX, fm.fpioa.UART1_RX, force=True) # UART_RX是PIN2
    fm.register(board_info.LED_B,fm.fpioa.GPIO0)                   
    
    led_r=GPIO(GPIO.GPIO0,GPIO.OUT)#操作设置GPIO模式
    
    uart_1 = UART(UART.UART1, 115200, 8, 0, 0, timeout=1000, read_buf_len=4096) # 申请串口
    print("UART TX/RX TEST ON")    

    condLock = threading.Condition() # 条件锁对象
    # 设置线程
    Led_Thread = led_thread(1, "Led_thread", args=(led_r,uart_1,))
    Uart_Thread =uart_thread(2,"uart_thread",args=(uart_1,))
    
    Led_Thread.star()
    Uart_Thread.start()
    
    Led_Thread.join()
    Uart_Thread.join()    

    print("UART TX/RX TEST OFF")
    
    fm.unregister(board_info.LED_B) #释放LED_B绑定的GPIO0
    
    uart_1.deinit()
    del uart_1
    del led_r   



Four. Summary

To operate the hardware IO of the K210, it is often necessary to map the function to be operated through a mapping operation , and the function of the mapping operation is provided by the fm library. If you want to operate GPIO, you need to use the GPIO module in the Maix module, and you need to use the machine module to use UART/PWM/I2C.

The multi-threaded operation of Maix py is relatively cheap and does not support threading, so it is not recommended to use it.

5. References

Mirco py document
Sipeed official document
py threading lock usage

Guess you like

Origin blog.csdn.net/weixin_46185705/article/details/128684935