diff --git a/content/micropython/02.environment/00.online-editor/online-editor.md b/content/micropython/02.environment/00.online-editor/online-editor.md index 890357dc61..010faf9cc4 100644 --- a/content/micropython/02.environment/00.online-editor/online-editor.md +++ b/content/micropython/02.environment/00.online-editor/online-editor.md @@ -18,7 +18,7 @@ In this tutorial, we will take a look at how we can access it, and test it out b ## Setting Up -***To follow these steps, you will need to have MicroPython installed on your board. Haven't done this yet? Don't worry, check out the [Installing MicroPython](/micropython/environment/code-editor) guide.*** +***To follow these steps, you will need to have MicroPython installed on your board. Haven't done this yet? Don't worry, check out the [Installing MicroPython](/micropython/first-steps/install-guide) guide.*** Setting up the online environment is quick and easy. Follow the steps below to achieve it: diff --git a/content/micropython/04.board-examples/portenta-c33/portenta-c33.md b/content/micropython/04.board-examples/portenta-c33/portenta-c33.md new file mode 100644 index 0000000000..4c9a21e329 --- /dev/null +++ b/content/micropython/04.board-examples/portenta-c33/portenta-c33.md @@ -0,0 +1,327 @@ +--- +title: 'Portenta C33' +description: 'Learn how to use specific features on the Portenta C33 using MicroPython' +author: 'Karl Söderby' +--- + +In this guide, you will information related only to the [Arduino® Portenta C33](https://store.arduino.cc/products/portenta-c33) and MicroPython. + +## Pinout Mapping + +The Portenta C33 has two ways its pins are physically available: through its MKR-styled connectors and its High-Density connectors. Most pins are referred to via their port name or function. In the image below, the Portenta C33 MKR-styled connectors pinout is shown. + +![Portenta C33 MKR-styled connectors pinout](assets/portenta33_MKR_pinout.png) + +The MKR-styled connectors pinout is mapped in MicroPython as follows: + +| **Arduino Pin Mapping** | **MicroPython Pin Mapping** | +|:-----------------------:|:---------------------------:| +| `P006`/`A0` | `P006` | +| `P005`/`A1` | `P005` | +| `P004`/`A2` | `P004` | +| `P002`/`A3` | `P002` | +| `P001`/`A4` | `P001` | +| `P015`/`A5` | `P015` | +| `P014`/`A6` | `P014` | +| `P105`/`D0` | `P105` | +| `P106`/`D1` | `P106` | +| `P111`/`D2` | `P111` | +| `P303`/`D3` | `P303` | +| `P401`/`D4` | `P401` | +| `P210`/`D5` | `P210` | +| `P602` | `P602` | +| `P110` | `P110` | +| `P408` | `P408` | +| `P407` | `P407` | +| `P315` | `P315` | +| `P204` | `P204` | +| `P900` | `P900` | +| `P402` | `P402` | +| `P601` | `P601` | + +The complete MicroPython pinout is available [here](https://github.com/micropython/micropython/blob/master/ports/renesas-ra/boards/ARDUINO_PORTENTA_C33/pins.csv). + +## Input/Output Pins + +The `Pin` class in the `machine` module is essential for controlling Input/Output (I/O) pins of the Portenta C33 board. These pins are crucial for a wide range of applications, including reading sensor data, controlling actuators, and interfacing with other hardware components. + +### Pin Initialization + +To begin using an I/O pin of the Portenta C33 board with MicroPython, you need to initialize it using the `Pin` class from the `machine` module. This involves specifying the pin identifier and its mode (input, output, etc.). + +```python +from machine import Pin + +# Initializing pin P107 as an output +p107 = Pin('P107', Pin.OUT) +``` + +### Configuring Pin Modes + +You can configure a pin as an input or output. For input pins, it's often useful to activate an internal pull-up or pull-down resistor. This helps to stabilize the input signal, especially in cases where the pin is reading a mechanical switch or a button. + +```python +# Configuring pin P105 as an input with its pull-up resistor enabled +p105 = Pin('P105', Pin.IN, Pin.PULL_UP) +``` + +### Reading from and Writing to Pins + +To read a digital value from a pin, use the `.value()` method without any arguments. This is particularly useful for input pins. Conversely, to write a digital value, use the `.value()` method with an argument. Passing `1` sets the pin to `HIGH`, while `0` sets it to `LOW`. This is applicable to output pins. + +```python +# Reading from P105 +pin_value = p105.value() + +# Writing to P107 +p107.value(1) # Set p2 to high +``` + +### Advanced Pin Configuration + +The Pin class allows dynamic reconfiguration of pins and setting up interrupt callbacks. This feature is essential for creating responsive and interactive applications. + +```python +# Reconfiguring P105 as an input with a pull-down resistor +p105.init(Pin.IN, Pin.PULL_DOWN) + +# Setting up an interrupt on P105 +p105.irq(lambda p: print("- IRQ triggered!", p)) +``` + +### Practical Example + +In this example, we will configure one pin as an input to read the state of a button and another pin as an output to control an LED. The LED will turn on when the button is pressed and off when it's released. + +```python +from machine import Pin +import time + +# Configure pin P107 as an output (for the LED) +led = Pin('P107', Pin.OUT_PP) + +# Configure pin P105 as input with pull-up resistor enabled (for the button) +button = Pin('P105', Pin.IN, Pin.PULL_UP) + +while True: + # Read the state of the button + button_state = button.value() + if button_state == 0: + # Turn on LED if button is pressed (button_state is LOW) + led.value(1) + else: + # Turn off LED if button is not pressed (button_state is HIGH) + led.value(0) + + # Short delay to debounce the button + time.sleep(0.1) +``` + +This practical example demonstrates controlling an LED based on a button's state. The LED, connected to pin `P107` (configured as an output), is turned on or off depending on the button's input read from pin `P105` (set as an input with a pull-up resistor). The main loop continually checks the button's state; pressing the button fixes the LED on while releasing it turns the LED off. A brief delay is included for debouncing, ensuring stable operation without false triggers from the button. + +## Analog to Digital Converter + +The `ADC` class in MicroPython provides an interface for the Analog-to-Digital (ADC) converter of the Portenta C33 board, enabling the measurement of continuous voltages and their conversion into discrete digital values. This functionality is crucial for applications that, for example, require reading from analog sensors. The `ADC` class represents a single endpoint for sampling voltage from an analog pin and converting it to a digital value. + +The available ADC pins of the Portenta C33 board in MicroPython are the following: + +| **Available ADC Pins** | +|:----------------------:| +| `P006` | +| `P005` | +| `P004` | +| `P002` | +| `P001` | +| `P015` | +| `P014` | +| `P000` | + +### Initializing the ADC + +First, to use an ADC of the Portenta C33 board, create an ADC object associated with a specific pin. This pin will be used to read analog values. + +```python +from machine import ADC + +# Create an ADC object on a specific pin +adc = ADC(pin) +``` + +### Reading Analog Values + +You can read analog values as raw values using the `read_u16()` method. This method returns a raw integer from 0-65535, representing the analog reading. + +```python +# Reading a raw analog value +val = adc.read_u16() +``` + +### Practical Example + +This example demonstrates the use of the `ADC` class to read values from a potentiometer on the Portenta C33 board. First, connect your potentiometer to the Portenta C33 board. One outer pin goes to `GND`, the other to `3V3`, and the middle pin to an analog-capable I/O pin, such as `P006`. This setup creates a variable voltage divider, with the voltage at the center pin changing as you adjust the potentiometer. + +```python +from machine import ADC, Pin +import time + +# Initialize the ADC on the potentiometer-connected pin +pot_pin = Pin('P006') +pot_adc = ADC(pot_pin) + +while True: + # Read the raw analog value + raw_value = pot_adc.read_u16() + print("- Potentiometer raw value:", raw_value) + + # Delay for readability + time.sleep(0.1) +``` +The example starts by importing the necessary modules and setting up the ADC on a pin connected to a potentiometer (`P006`). The ADC object (`pot_adc`) is used to interface with the potentiometer. Inside the loop, the analog value from the potentiometer is continuously read using the `read_u16()` method that provides a raw integer value scaled between `0` and `65535`, reflecting the potentiometer's position. The analog value value is printed to the console, and a short delay is included in the loop to ensure the output is readable. + +## Pulse Width Modulation + +Pulse Width Modulation (PWM) is a method to emulate an analog output using a digital pin. It does this by rapidly toggling the pin between low and high states. Two primary aspects define PWM behavior: + +- **Frequency**: This is the speed at which the pin toggles between low and high states. A higher frequency means the pin toggles faster. +- **Duty cycle**: This refers to the ratio of the high state duration to the total cycle duration. A 100% duty cycle means the pin remains high all the time, while a 0% duty cycle means it stays low. + +The available PWM pins of the Portenta C33 board in MicroPython are the following: + +| **Available PWM Pins** | +|:----------------------:| +| `P105` | +| `P106` | +| `P111` | +| `P303` | +| `P401` | +| `P601` | + +### Setting Up PWM + +To use PWM, start by initializing a pin and then creating a PWM object associated with that pin. + +```python +import machine + +# Initialize a pin for PWM (e.g., pin P105) +p105 = machine.Pin('P105') +pwm1 = machine.PWM(p105) +``` + +### Configuring PWM Parameters + +The frequency and duty cycle of the PWM signal are set based on the specific needs of your application: + +```python +# Set the frequency to 500 Hz +pwm1.freq(500) + +# Adjusting the duty cycle to 50 for 50% duty +pwm1.duty(50) +``` + +### Checking PWM Configuration + +You can check the current configuration of the PWM object by printing it: + +```python +# Will show the current frequency and duty cycle +print(pwm1) +``` + +Retrieve the frequency and duty cycle values: + +```python +current_freq = pwm1.freq() +current_duty = pwm1.duty() +``` + +### Deinitializing PWM + +When PWM is no longer needed, the pin can be deinitialized: + +```python +pwm1.deinit() +``` + +### Practical Example + +In this example, we will use PWM to control the brightness of an LED connected to pin `P105` of the Portenta C33 board. + +```python +import machine +import time + +# Configure the LED pin and PWM +led_pin = machine.Pin('P105') +led_pwm = machine.PWM(led_pin) +led_pwm.freq(500) + +# Loop to vary brightness +while True: + # Increase brightness + for duty in range(100): + led_pwm.duty(duty) + time.sleep(0.001) + + # Decrease brightness + for duty in range(100, -1, -1): + led_pwm.duty(duty) + time.sleep(0.001) +``` + +## Real-Time Clock + +The `RTC` class in MicroPython provides a way to manage and utilize the Real-Time Clock (RTC) of the Portenta C33 board. This feature is essential for applications that require accurate timekeeping, even when the main processor is not active. The RTC maintains accurate time and date, functioning independently from the main system. It continues to keep track of the time even when the board is powered off, as long as it's connected to a power source like a battery. + +### Initializing the RTC + +To use the RTC, first create an RTC object. This object is then used to set or read the current date and time. + + +```python +import machine + +# Create an RTC object +rtc = machine.RTC() +``` + +### Setting and Getting Date and Time + +The RTC allows you to set and retrieve the current date and time. The date and time are represented as an 8-tuple format. + +```python +# Setting the RTC date and time +rtc.datetime((2024, 1, 4, 4, 20, 0, 0, 0)) + +# Getting the current date and time +current_datetime = rtc.datetime() +print("- Current date and time:", current_datetime) +``` + +The 8-tuple for the date and time follows the format `(year, month, day, weekday, hours, minutes, seconds, subseconds)`. + +### Practical Example + +A practical use case for the RTC is to add timestamps to sensor data readings. By setting the current time on the RTC, you can then append an accurate timestamp each time a sensor value is logged. + +```python +import machine + +# Initialize the RTC and set the current datetime +rtc.datetime((2024, 1, 4, 4, 20, 0, 0, 0)) + +# Function to read a sensor value (placeholder) +def read_sensor(): + # Replace with actual sensor reading logic + return 42 + +# Read sensor value and get the current time +sensor_value = read_sensor() +timestamp = rtc.datetime() + +# Output the sensor value with its timestamp +print("- Sensor value at ", timestamp, ":", sensor_value) +``` + +In this example, every sensor reading is accompanied by a timestamp, which can be crucial for data analysis or logging purposes. The RTC's ability to maintain time independently of the main system's power status makes it reliable for time-sensitive applications. diff --git a/content/micropython/04.board-examples/portenta-h7/portenta-h7.md b/content/micropython/04.board-examples/portenta-h7/portenta-h7.md new file mode 100644 index 0000000000..e04343fa3b --- /dev/null +++ b/content/micropython/04.board-examples/portenta-h7/portenta-h7.md @@ -0,0 +1,563 @@ +--- +title: 'Portenta H7' +description: 'Learn how to use specific features on the Portenta H7 using MicroPython' +author: 'Karl Söderby' +--- + +![Portenta H7.](assets/portenta.png) + +In this guide, you will information related only to the [Arduino® Portenta H7](https://store.arduino.cc/en-se/products/portenta-h7) and MicroPython. + +***Note that the [Portenta H7 Lite](/hardware/portenta-h7-lite) and [Portenta H7 Lite Connected](/hardware/portenta-h7-lite-connected) boards are compatible with most examples listed here, as they are variations of the Portenta H7.*** + +### GPIO Map + +Most of the pins are referred to via their port name or their function. Please refer to the list below to see which function corresponds to which port on the Portenta H7. + +| Arduino | STM32H747 | +| ---------------- | --------- | +| PA0 | PA0 | +| PA1 | PA1 | +| PA2 | PA2 | +| PA3 | PA3 | +| PA4 | PA4 | +| PA5 | PA5 | +| PA6 | PA6 | +| PA7 | PA7 | +| PA8 | PA8 | +| PA9 | PA9 | +| PA10 | PA10 | +| PA11 | PA11 | +| PA12 | PA12 | +| PA13 | PA13 | +| PA14 | PA14 | +| PA15 | PA15 | +| PB0 | PB0 | +| PB1 | PB1 | +| PB2 | PB2 | +| PB3 | PB3 | +| PB4 | PB4 | +| PB5 | PB5 | +| PB6 | PB6 | +| PB7 | PB7 | +| PB8 | PB8 | +| PB9 | PB9 | +| PB10 | PB10 | +| PB11 | PB11 | +| PB12 | PB12 | +| PB13 | PB13 | +| PB14 | PB14 | +| PB15 | PB15 | +| PC0 | PC0 | +| PC1 | PC1 | +| PC2 | PC2 | +| PC3 | PC3 | +| PC4 | PC4 | +| PC5 | PC5 | +| PC6 | PC6 | +| PC7 | PC7 | +| PC8 | PC8 | +| PC9 | PC9 | +| PC10 | PC10 | +| PC11 | PC11 | +| PC12 | PC12 | +| PC13 | PC13 | +| PC14 | PC14 | +| PC15 | PC15 | +| PD0 | PD0 | +| PD1 | PD1 | +| PD2 | PD2 | +| PD3 | PD3 | +| PD4 | PD4 | +| PD5 | PD5 | +| PD6 | PD6 | +| PD7 | PD7 | +| PD8 | PD8 | +| PD9 | PD9 | +| PD10 | PD10 | +| PD11 | PD11 | +| PD12 | PD12 | +| PD13 | PD13 | +| PD14 | PD14 | +| PD15 | PD15 | +| PE0 | PE0 | +| PE1 | PE1 | +| PE2 | PE2 | +| PE3 | PE3 | +| PE4 | PE4 | +| PE5 | PE5 | +| PE6 | PE6 | +| PE7 | PE7 | +| PE8 | PE8 | +| PE9 | PE9 | +| PE10 | PE10 | +| PE11 | PE11 | +| PE12 | PE12 | +| PE13 | PE13 | +| PE14 | PE14 | +| PE15 | PE15 | +| PF0 | PF0 | +| PF1 | PF1 | +| PF2 | PF2 | +| PF3 | PF3 | +| PF4 | PF4 | +| PF5 | PF5 | +| PF6 | PF6 | +| PF7 | PF7 | +| PF8 | PF8 | +| PF9 | PF9 | +| PF10 | PF10 | +| PF11 | PF11 | +| PF12 | PF12 | +| PF13 | PF13 | +| PF14 | PF14 | +| PF15 | PF15 | +| PG0 | PG0 | +| PG1 | PG1 | +| PG2 | PG2 | +| PG3 | PG3 | +| PG4 | PG4 | +| PG5 | PG5 | +| PG6 | PG6 | +| PG7 | PG7 | +| PG8 | PG8 | +| PG9 | PG9 | +| PG10 | PG10 | +| PG11 | PG11 | +| PG12 | PG12 | +| PG13 | PG13 | +| PG14 | PG14 | +| PG15 | PG15 | +| PH0 | PH0 | +| PH1 | PH1 | +| PH2 | PH2 | +| PH3 | PH3 | +| PH4 | PH4 | +| PH5 | PH5 | +| PH6 | PH6 | +| PH7 | PH7 | +| PH8 | PH8 | +| PH9 | PH9 | +| PH10 | PH10 | +| PH11 | PH11 | +| PH12 | PH12 | +| PH13 | PH13 | +| PH14 | PH14 | +| PH15 | PH15 | +| PI0 | PI0 | +| PI1 | PI1 | +| PI2 | PI2 | +| PI3 | PI3 | +| PI4 | PI4 | +| PI5 | PI5 | +| PI6 | PI6 | +| PI7 | PI7 | +| PI8 | PI8 | +| PI9 | PI9 | +| PI10 | PI10 | +| PI11 | PI11 | +| PI12 | PI12 | +| PI13 | PI13 | +| PI14 | PI14 | +| PI15 | PI15 | +| PJ0 | PJ0 | +| PJ1 | PJ1 | +| PJ2 | PJ2 | +| PJ3 | PJ3 | +| PJ4 | PJ4 | +| PJ5 | PJ5 | +| PJ6 | PJ6 | +| PJ7 | PJ7 | +| PJ8 | PJ8 | +| PJ9 | PJ9 | +| PJ10 | PJ10 | +| PJ11 | PJ11 | +| PJ12 | PJ12 | +| PJ13 | PJ13 | +| PJ14 | PJ14 | +| PJ15 | PJ15 | +| PK0 | PK0 | +| PK1 | PK1 | +| PK2 | PK2 | +| PK3 | PK3 | +| PK4 | PK4 | +| PK5 | PK5 | +| PK6 | PK6 | +| PK7 | PK7 | +| UART1_TX | PA9 | +| UART1_RX | PA10 | +| UART4_TX | PA0 | +| UART4_RX | PI9 | +| UART6_TX | PG14 | +| UART6_RX | PG9 | +| UART8_TX | PJ8 | +| UART8_RX | PJ9 | +| ETH_RMII_REF_CLK | PA1 | +| ETH_MDIO | PA2 | +| ETH_RMII_CRS_DV | PA7 | +| ETH_MDC | PC1 | +| ETH_RMII_RXD0 | PC4 | +| ETH_RMII_RXD1 | PC5 | +| ETH_RMII_TX_EN | PG11 | +| ETH_RMII_TXD0 | PG13 | +| ETH_RMII_TXD1 | PG12 | +| USB_HS_CLK | PA5 | +| USB_HS_STP | PC0 | +| USB_HS_NXT | PH4 | +| USB_HS_DIR | PI11 | +| USB_HS_D0 | PA3 | +| USB_HS_D1 | PB0 | +| USB_HS_D2 | PB1 | +| USB_HS_D3 | PB10 | +| USB_HS_D4 | PB11 | +| USB_HS_D5 | PB12 | +| USB_HS_D6 | PB13 | +| USB_HS_D7 | PB5 | +| USB_HS_RST | PJ4 | +| USB_DM | PA11 | +| USB_DP | PA12 | +| BOOT0 | BOOT0 | +| DAC1 | PA4 | +| DAC2 | PA5 | +| LEDR | PK5 | +| LEDG | PK6 | +| LEDB | PK7 | +| I2C1_SDA | PB7 | +| I2C1_SCL | PB6 | +| I2C3_SDA | PH8 | +| I2C3_SCL | PH7 | +| -WL_REG_ON | PJ1 | +| -WL_HOST_WAKE | PJ5 | +| -WL_SDIO_0 | PC8 | +| -WL_SDIO_1 | PC9 | +| -WL_SDIO_2 | PC10 | +| -WL_SDIO_3 | PC11 | +| -WL_SDIO_CMD | PD2 | +| -WL_SDIO_CLK | PC12 | +| -BT_RXD | PF6 | +| -BT_TXD | PA15 | +| -BT_CTS | PF9 | +| -BT_RTS | PF8 | +| -BT_REG_ON | PJ12 | +| -BT_HOST_WAKE | PJ13 | +| -BT_DEV_WAKE | PJ14 | +| -QSPI2_CS | PG6 | +| -QSPI2_CLK | PF10 | +| -QSPI2_D0 | PD11 | +| -QSPI2_D1 | PD12 | +| -QSPI2_D2 | PF7 | +| -QSPI2_D3 | PD13 | + + +### I/O Pins + +To access the I/O pins, you can use the `Pin` module from the `pyb` library. + +```python +from pyb import Pin +``` + +To reference a pin on the Portenta, you can use the `Pin()` constructor. The first argument you have to provide is the pin you want to use. The second parameter, `mode`, can be set as: `Pin.IN`, `Pin.OUT_PP`, `Pin.OUT_OD`, `Pin.AF_PP`, `Pin.AF_OD` or `Pin.ANALOG`. An explanation of the pin modes can be found [here](https://docs.openmv.io/library/pyb.Pin.html#methods). The third parameter, `pull`, represents the pull mode. It can be set to: `Pin.PULL_NONE`, `Pin.PULL_UP` or `Pin.PULL_DOWN`. E.g.: + +```python +pin0 = Pin('P0', mode, pull) +``` + +To get the logic level of a pin, call `.value()`. It will return a 0 or a 1. This corresponds to `LOW` and `HIGH` in Arduino terminology. + +```python +pin0.value() +``` + +### PWM + +To use PWM, you import the `pyb`, `time`, `Pin`, `Timer` modules. + +```python +import pyb +import time +from pyb import Pin, Timer +``` + +First you need to choose the pin you want to use PWM with. + +```python +pin1 = Pin("PC6", Pin.OUT_PP, Pin.PULL_NONE) +``` + +Create a timer for the PWM, where you set the ID and the frequency. + +```python +timer1 = Timer(3, freq=1000) +``` + +Then you need to start a PWM channel with the timer object. + +```python +channel1 = timer1.channel(1, Timer.PWM, pin=pin1, pulse_width=0) +``` + +Get or set the pulse width value on a channel. To get, pass no arguments. To set, give a value as an argument. + +```python +channel1.pulse_width(Width) +``` + +### RGB LED + +The Portenta H7 has built-in RGB that can be used as feedback for applications. Using the `pyb` library, you can easily define the different LED colors on the Portenta. + +For this you will use the `pyb` library. + +```python +import pyb +``` + +Now you can easily define the different colors of the built in LED. + +```python +redLED = pyb.LED(1) +greenLED = pyb.LED(2) +blueLED = pyb.LED(3) +``` + +And then control them in our script. + +```python +redLED.on() +redLED.off() + +greenLED.on() +greenLED.off() + +blueLED.on() +blueLED.off() +``` + +You could also set a custom intensity for our LED lights. This ranges between the values 0 (off) and 255 (full on). Below you can see an example of how to set the intensity on our different LED lights. + +```python +redLED.intensity(128) +greenLED.intensity(64) +blueLED.intensity(50) +``` + +If no argument is given in the `.intensity()` function, it will return the LED intensity. + +### Communication + +Like other Arduino® products, the Portenta H7 features dedicated pins for different protocols. + +#### SPI + +The pins used for SPI on the Portenta H7 are the following: + + +| Pin | Function | +| :---: | :------: | +| PI0 | CS | +| PC3 | COPI | +| PI1 | CK | +| PC2 | CIPO | + +You can refer to the [pinout](#gpio-map-2) above to find them on the board. + +First, you have to import the relevant module from `pyb`. + +```python +from pyb import SPI +``` + +When you initialize SPI, the only thing you need to state is the bus, which will always be `2` on the Portenta H7; this is the only available bus. The rest of the arguments are optional. But if it is needed, you can state the mode of the SPI device as either `SPI.MASTER` or `SPI.SLAVE`, you can also manually set the `baudrate` of the device. `Polarity` can be set to 0 or 1, and is the logic level the idle clock line sits at (HIGH or LOW). `Phase` can be 0 or 1 to sample data on the first (0) or second (1) clock edge. + +```python +spi = SPI(2, SPI.MASTER, baudrate=100000, polarity=0, phase=0) +``` + +Now, if you want to send data over SPI, you simply call `.send()` inside the arguments you want to send. `data` is the data to send, which could be an integer (dataInt) or a buffer object (dataBuffer). It is optional to set the `timeout`, it indicates the timeout in milliseconds to wait for the send. + +```python +dataInt = 21 +dataBuffer = bytearray(4) +spi.send(data, timeout=5000) +``` + +Similarly, if you want to receive data over SPI, you call `.recv()`. `data` indicates the number of bytes to receive, this can be an integer (dataInt) or a buffer (dataBuffer), which will be filled with received bytes. It is optional to set the `timeout`, which is the time in milliseconds to wait for the receive. + +```python +dataInt = 0 +dataBuffer = bytearray(4) +SPI.recv(data, timeout=5000) +``` + +#### I2C + +The pins used for I2C (Inter-Integrated Circuit) on the Portenta H7 are the following: + +| Pin | Function | +| :---: | :------: | +| PH8 | SDA | +| PH7 | SCL | + +You can refer to the [pinout](##gpio-map-2) above to find them on the board. + +To use the I2C, you import the relevant module. + +```python +from pyb import I2C +``` + +You can now create the I2C object. To create an I2C object you need to state the bus, this indicates what pins you will use for I2C. Giving bus a value of `3` starts I2C on the SCL and SDA pins on the Portenta H7. There are 4 I2C buses on the Portenta H7. + +```python +i2c = I2C(3) +``` + +Now that the object is created, you can initialize it. You need to decide if your device is going to be a controller (I2C.MASTER) or a reader (I2C.SLAVE). If it is a reader device, you also need to set the `address`. You can then set a baudrate if you need to. + +```python +i2c.init(I2C.MASTER, addr=address, baudrate=100000) +``` + +To receive data on the bus, you call the `.recv()` function. In the functions arguments `data` is the number of bytes to receive, it can be an integer (dataInt) or a buffer (dataBuffer), which will be filled with received bytes. `addr` is the address to receive from, this is only required in controller mode. `timeout` indicates how many milliseconds to wait for the receive. The code below shows how to receive and print your data in the OpenMV serial terminal. + +```python +dataInt = 0 +dataBuffer = bytearray(4) +receivedData = i2c.recv(data, addr=0, timeout=5000) +Print(receivedData) +``` + +To send data on the bus, you can call the `.send()` function. In the functions arguments `data` is the data to send, an integer (dataInt) or a buffer object (dataBuffer). `addr` is the address to send to, this is only required in controller mode. `timeout` indicates how many milliseconds to wait for the send. + +```python +dataInt = 412 +dataBuffer = bytearray(4) +i2c.send(data, addr=0, timeout=5000) +``` + +If you need to make sure that devices are connected to the I2C bus, you can use the `.scan()` function. It will scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond. It only works when in controller mode. + +```python +i2c.scan() +``` + +#### UART + +The pins used for UART on the Portenta H7 are the following: + +| Pin | Function | +| :---: | :------: | +| PA10 | RX | +| PA9 | TX | + +You can refer to the [pinout](#gpio-map-2) above to find them on the board. + +To use the UART, you need to import the relevant module. + +```python +from pyb import UART +``` + +To create the UART object, you need to indicate the UART bus, the Portenta has 3 UART buses, but there is only on UART bus available to use with OpenMV through the boards pins. + +```python +uart = UART(1) +``` + +With the object created, you can initialize it with `init`. When initilazing, you can set the `baudrate`. `bits` is the number of bits per character (7, 8 or 9). `parity` can be set to `None`, `0` (even) or `1` (odd). `stop` is the number of stop bits, 1 or 2. `flow` sets the flow control type, can be 0, UART.RTS, UART.CTS or UART.RTS | UART.CTS. More information on this can be found [here](https://docs.openmv.io/library/pyb.UART.html#flow-control). `timeout` is the time in milliseconds to wait for writing/reading the first character. `timeout_char` is the timeout in milliseconds to wait between characters while writing or reading. `read_buf_len` is the character length of the read buffer (0 to disable). + +```python +uart.init(baudrate, bits=8, parity=None, stop=1, timeout=0, flow=0, timeout_char=0, read_buf_len=64) +``` + +To read from UART, you can call `.read()`. If `bytes` is specified then read at most that many bytes. If `bytes` is not given then the method reads as much data as possible. It returns after the timeout has elapsed. The example code below will read bytes received through uart into an array and then print it in the serial terminal. + +```python +array = bytearray(5) +uart.read(array) +print(array) +``` + +If you intend to write over UART, you can call `.write()`. The function writes `buffer` of bytes to the bus. If characters are 7 or 8 bits wide then each byte is one character. If characters are 9 bits wide then two bytes are used for each character and `buffer` must contain an even number of bytes. + +```python +uart.write(buffer) +``` + +#### Wi-Fi® + +To use Wi-Fi® you first need to import the relevant library. + +```python +import network +``` + +Then you need to define the Wi-Fi® networks SSID and put that in a variable. You must do the same for the networks password. + +```python +SSID='' +PASSWORD='' +``` + +Next, you can create a WLAN network interface object. In the argument you can enter `network.STA_IF`, which indicates that your device will be a client and connect to a Wi-Fi® access point. + +```python +wlan = network.WLAN(network.STA_IF) +``` + +To activate the network interface, you can simply call `.activate` with the argument `True`. + +```python +wlan.active(True) +``` + +Now you can decide which network to connect to. Here it is where the `SSID` and `PASSWORD` variables come in handy. + +```python +wlan.connect(SSID, PASSWORD, timeout=30000) +``` + +If you need to troubleshoot, the connection `.status()` can be used. This function will return a value that describes the connection status. It will also let you know what went wrong with the connection in case it failed. + +```python +wlan.status() +``` + +### Audio + +If you want to use audio with the Portenta H7, you first need to include the `audio` module. Another helpful module is `micro_speech`, this runs Google's TensorFlow Lite for Microcontrollers Micro Speech framework for voice recognition. + +```python +import audio, micro_speech +``` + +Next you need to initialize the audio object. In the initialization you can decide how many `channels` to use, it is possible to use either 1 or 2 channels. Frequency decides the sample frequency. Using a higher sample frequency results in a higher noise flow, meaning less effective bits per sample. By default audio samples are 8-bits with 7-bits of effective dynamic range. `gain_db` sets the microphone gain to use. `highpass` is the high pass filter cut off given the target sample frequency. + +```python +audio.init(channels=2, frequency=16000, gain_db=24, highpass=0.9883) +``` + +If you need to deinitialize the audio object, you can simply call `deint()`. + +```python +audio.deint() +``` + +To use micro_speech, you first need to create a micro_speech object. You can create this object in the variable `speech`. + +```python +speech = micro_speech.MicroSpeech() +``` + +Next you can start streaming audio into the `micro_speech` object, to do this you can call `audio.start_streaming()`. Here you can pass the `micro_speech` object as the argument, this will fill the object with audio samples. The MicroSpeech module will compute the FFT of the audio samples and keep a sliding window internally of the FFT the last 100ms or so of audio samples received as features for voice recognition. + +```python +audio.start_streaming(speech.audio_callback) +``` + +If you need to stop the audio streaming, you can call `.stop_streaming()`. + +```python +audio.stop_streaming() +``` diff --git a/content/micropython/05.modulinos/01.installation/installation.md b/content/micropython/05.modulinos/01.installation/installation.md index 4f9b069a84..5b652ec985 100644 --- a/content/micropython/05.modulinos/01.installation/installation.md +++ b/content/micropython/05.modulinos/01.installation/installation.md @@ -42,13 +42,9 @@ To follow this tutorial, we will need to install MicroPython on our Arduino boar To program Modulinos using MicroPython we must first install the Modulino package. It's where all the code, necessary to interact with the Modulinos is being stored. -There are two ways of installing a package: -- Through a terminal -- - ### Terminal Installation -The easiest way of installing it is using `mpremote`. Currently, we will need a version of Python installed on our computer. +To install a module, we can use `mpremote`. Currently, we will need a version of Python installed on our computer. 1. Open a terminal, and write the following line: ```bash @@ -65,9 +61,9 @@ The easiest way of installing it is using `mpremote`. Currently, we will need a ```bash /dev/cu.usbmodem101 ecda3b60a4dccb3f 2341:056b Arduino Nano ESP32 ``` - - The port here is `/dev/cu.usbmodem101`. Copy this. + The port here is `/dev/cu.usbmodem101`. Copy this. -3. Now, run the following the command. Make sure to replace `` with the port of our device obtained in the previous step. +1. Now, run the following the command. Make sure to replace `` with the port of our device obtained in the previous step. ```bash mpremote connect mip install github:arduino/arduino-modulino-mpy ``` @@ -75,7 +71,7 @@ The easiest way of installing it is using `mpremote`. Currently, we will need a Upon completion, we should see something like this in the terminal, to verify the success of the installation: ![Successful installation.](assets/package-installed.png) -4. Great job. We have now installed the Modulino package on our board! +2. Great job. We have now installed the Modulino package on our board! **Troubleshooting:** - Make sure your board is connected to your computer.