Browse Source

stm32/boards/LEGO_HUB_NO7: Add LEGO Hub No. 7 board definition.

This adds support for the LEGO Hub No. 7, aka LEGO Technic Small hub, aka
LEGO SPIKE Essential hub.  This board is largely similar to Hub No. 6:

- Same MCU (STM32F413 - different packaging with fewer pins).
- Same Bluetooth chip (TI CC2564).
- Same IMU chip.
- Similar external flash chip - 4MiB instead of 32MiB.
- 2 I/O ports instead of 6.
- No display - only status and battery LEDs.
- Different LED driver chip.
- Only 1 button which is also the power button.
- No speaker.

Signed-off-by: David Lechner <david@pybricks.com>
pull/8761/merge
David Lechner 2 years ago
committed by Damien George
parent
commit
10f85fee18
  1. 135
      ports/stm32/boards/LEGO_HUB_NO7/README.md
  2. 3
      ports/stm32/boards/LEGO_HUB_NO7/bdev.c
  3. 3
      ports/stm32/boards/LEGO_HUB_NO7/bluetooth_init_cc2564C_1.5.c
  4. 13
      ports/stm32/boards/LEGO_HUB_NO7/board.json
  5. 212
      ports/stm32/boards/LEGO_HUB_NO7/board_init.c
  6. 6
      ports/stm32/boards/LEGO_HUB_NO7/cc2564.c
  7. 190
      ports/stm32/boards/LEGO_HUB_NO7/hub_display.c
  8. 4
      ports/stm32/boards/LEGO_HUB_NO7/hub_display.h
  9. 5
      ports/stm32/boards/LEGO_HUB_NO7/manifest.py
  10. 152
      ports/stm32/boards/LEGO_HUB_NO7/mpconfigboard.h
  11. 50
      ports/stm32/boards/LEGO_HUB_NO7/mpconfigboard.mk
  12. 114
      ports/stm32/boards/LEGO_HUB_NO7/pins.csv
  13. 23
      ports/stm32/boards/LEGO_HUB_NO7/stm32f4xx_hal_conf.h

135
ports/stm32/boards/LEGO_HUB_NO7/README.md

@ -0,0 +1,135 @@
LEGO Hub No.7
=============
This board definition is for the LEGO Hub No. 7, a LEGO control unit with 1 button,
2 RGB LEDs, 2 Powered Up ports, 6-DOF sensor, Bluetooth, USB, 4MiB external SPI
flash storage, and a rechargeable battery.
Features that are currently supported:
- standard MicroPython
- machine and bluetooth modules
- filesystem
- USB VCP, MSC and HID
The Hub has a bootloader preinstalled at 0x08000000 (which is 32kiB in size) which
cannot be erased. This bootloader is entered by holding down the button for 5 seconds,
at which point the USB DFU device appears. If the battery is installed then the
RGB LED will flash purple. If the battery is not installed, the LED will flash orange
briefly and then the hub will turn off (so having the battery installed is required).
When this bootloader is active, the flash from 0x08008000 and up can be erased
and programmed via USB DFU.
The built-in bootloader has some drawbacks: it cannot be entered programmatically,
and it does not keep the Hub powered up when running from battery (which requires
keeping BAT_PWR_EN high). As such, this board is configured to work with mboot as
a secondary bootloader: mboot is placed at 0x08008000 and the main application
firmware at 0x08010000. When mboot is installed it can be entered programatically
via machine.bootloader().
Backing up original Hub firmware
--------------------------------
Before installing MicroPython it is advised to backup the original LEGO firmware that
the Hub comes installed with. To do this, enter the built-in bootloader by holding
down the power button for 5 seconds while powering up the Hub via USB (you may
need to take out the battery and disconnect USB to power off the Hub first). Then
run the following command from the root of this repository:
$ cd ports/stm32
$ make BOARD=LEGO_HUB_NO7 backup-hub-firmware
This will create a file called `lego_hub_firmware.dfu`. Put this file in a safe
location. To restore it, enter the built-in bootloader again and run:
$ make BOARD=LEGO_HUB_NO7 restore-hub-firmware
This will restore the original firmware but not the filesystem. To recreate the
original filesystem the Hub must be updated using the appropriate LEGO PC
application.
Installing MicroPython
----------------------
You first need to build and install mboot, which only needs to be done once. From
the root of this repository run:
$ cd ports/stm32/mboot
$ make BOARD=LEGO_HUB_NO7
Now enter the built-in bootloader by holding down the power button for 5
seconds while powering up the Hub via USB (you may need to take out the battery
and disconnect USB to power off the Hub first). Then run:
$ make BOARD=LEGO_HUB_NO7 deploy
mboot should now be installed. To enter mboot, remove USB and the battery.
Connect the USB cable (the other end of the USB cable must be connected to
something that provides power). The status light should start cycling through
different colors. Replace the battery (the button will not work without the
battery present). Press the button to activate the desired boot mode:
- Status light is red - run application (normal boot).
- Status light is green - run application in factory file system mode.
- Status light is blue - run application in safe mode.
- Status light is white - start DFU on the USB port.
Now build MicroPython (start at the root of this repository):
$ cd mpy-cross
$ make
$ cd ../ports/stm32
$ make submodules
$ make BOARD=LEGO_HUB_NO7
And deploy to the Hub (making sure mboot DFU is active, the center button is
blinking red):
$ make BOARD=LEGO_HUB_NO7 deploy
If successful, the Hub should now appear as a USB serial and mass storage device.
Using MicroPython on the Hub
----------------------------
Access the MicroPython REPL using mpremote (pip install mpremote), or with any
serial terminal program.
To scan for BLE devices:
>>> import bluetooth
>>> ble = bluetooth.BLE()
>>> ble.irq(lambda *x: print(*x))
>>> ble.active(1)
>>> ble.gap_scan(2000, 625, 625)
Use help("modules") to see available built-in modules.
Updating MicroPython from the Hub's filesystem
----------------------------------------------
You can update the MicroPython application firmware using the instructions above
for installing the firmware for the first time. The Hub also supports updating
the application firmware from within MicroPython itself, using the on-board
filesystem.
To use this feature, build the firmware (see above for details) then gzip it and
copy the resulting file to the Hub (eg using mpremote):
$ make BOARD=LEGO_HUB_NO7
$ gzip build-LEGO_HUB_NO7/firmware.dfu
$ mpremote cp build-LEGO_HUB_NO7/firmware.dfu.gz :
Then get a REPL on the Hub and execute:
>>> import appupdate
>>> appupdate.update_app("firmware.dfu.gz")
You can alternatively run this REPL command using mpremote:
$ mpremote exec --no-follow "import appupdate; appupdate.update_app('firmware.dfu.gz')"
At that point the Hub should restart and the LED on the central button will flash
different colours. Once the update is complete the LED will stop flashing and the
Hub will appear again as a USB device. The application firmware is now updated
and you can remove the firmware.dfu.gz file if desired.

3
ports/stm32/boards/LEGO_HUB_NO7/bdev.c

@ -0,0 +1,3 @@
// LEGO_HUB_NO7 is identical to LEGO_HUB_NO6 in this regard.
#include "../LEGO_HUB_NO6/bdev.c"

3
ports/stm32/boards/LEGO_HUB_NO7/bluetooth_init_cc2564C_1.5.c

@ -0,0 +1,3 @@
// LEGO_HUB_NO7 is identical to LEGO_HUB_NO6 in this regard.
#include "../LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c"

13
ports/stm32/boards/LEGO_HUB_NO7/board.json

@ -0,0 +1,13 @@
{
"deploy": [
"../deploy.md"
],
"docs": "",
"features": [],
"images": [],
"mcu": "stm32f4",
"product": "Hub No.7",
"thumbnail": "",
"url": "",
"vendor": "LEGO"
}

212
ports/stm32/boards/LEGO_HUB_NO7/board_init.c

@ -0,0 +1,212 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021-2022 Damien P. George
* Copyright (c) 2022 David Lechner <david@pybricks.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mphal.h"
#include "irq.h"
void board_init(void) {
if (query_irq() == IRQ_STATE_DISABLED) {
enable_irq(IRQ_STATE_ENABLED);
}
// Enable 3V3 for all ports
mp_hal_pin_output(pyb_pin_PORT_3V3_EN);
mp_hal_pin_high(pyb_pin_PORT_3V3_EN);
// Port A
// Enable RX/TX buffer
mp_hal_pin_output(pyb_pin_PORTA_EN);
mp_hal_pin_low(pyb_pin_PORTA_EN);
// Port B
// Enable RX/TX buffer
mp_hal_pin_output(pyb_pin_PORTB_EN);
mp_hal_pin_low(pyb_pin_PORTB_EN);
}
#if BUILDING_MBOOT
#include "drivers/memory/spiflash.h"
#include "mboot/mboot.h"
#include "boardctrl.h"
#include "adc.h"
#include "hub_display.h"
#define RESET_MODE_NUM_STATES (4)
#define RESET_MODE_TIMEOUT_CYCLES (8)
// Location and value for the SPI flash update key. If this key exists at the defined
// location then mboot will attempt to do a filesystem-load update of the main firmware.
// This makes the update robust to power failures: if the update does not complete then
// it will be restarted the next time it powers up. Only when it fully completes will
// this key be erased, and then the application can run.
#define SPIFLASH_UPDATE_KEY_ADDR (1020 * 1024)
#define SPIFLASH_UPDATE_KEY_VALUE (0x12345678)
static void board_led_pattern(int reset_mode, uint16_t brightness) {
switch (reset_mode) {
case BOARDCTRL_RESET_MODE_NORMAL:
// set status light to red
hub_display_set(3, brightness);
hub_display_set(4, 0);
hub_display_set(5, 0);
break;
case BOARDCTRL_RESET_MODE_SAFE_MODE:
// set status light to green
hub_display_set(3, 0);
hub_display_set(4, brightness);
hub_display_set(5, 0);
break;
case BOARDCTRL_RESET_MODE_FACTORY_FILESYSTEM:
// set status light to blue
hub_display_set(3, 0);
hub_display_set(4, 0);
hub_display_set(5, brightness);
break;
case BOARDCTRL_RESET_MODE_BOOTLOADER:
// set status light to white
hub_display_set(3, brightness);
hub_display_set(4, brightness);
hub_display_set(5, brightness);
break;
}
hub_display_update();
}
static void board_battery_init(void) {
mp_hal_pin_config(pyb_pin_BAT_VMON_ADC, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
adc_config(ADC1, 12);
}
// returns true if the battery is pressed, otherwise false
static int board_battery_state(void) {
uint16_t value = adc_config_and_read_u16(ADC1, 6, ADC_SAMPLETIME_15CYCLES);
// If battery voltage is above USB voltage, then we consider the battery
// to be present.
return value > 41100; // 41100 is approx 5.5V
}
static void board_button_init(void) {
mp_hal_pin_input(pyb_pin_BUTTON);
}
// returns true if the button is pressed, otherwise false
static int board_button_state(void) {
// button is active low
return !mp_hal_pin_read(pyb_pin_BUTTON);
}
void board_mboot_cleanup(int reset_mode) {
board_led_pattern(0, 0);
hub_display_off();
}
void board_mboot_led_init(void) {
hub_display_on();
}
void board_mboot_led_state(int led, int state) {
if (state) {
hub_display_set(3 + led, 0x7fff);
} else {
hub_display_set(3 + led, 0);
}
hub_display_update();
}
int board_mboot_get_reset_mode(uint32_t *initial_r0) {
board_battery_init();
board_button_init();
int reset_mode = BOARDCTRL_RESET_MODE_NORMAL;
if (board_battery_state()) {
// Battery is present, check flash for update key and start an update if the key exists.
// Otherwise, boot normally.
// Initialise the external SPI flash.
MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG;
mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH);
// Read in the key.
uint32_t buf;
mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR, 4, (uint8_t *)&buf);
if (buf == SPIFLASH_UPDATE_KEY_VALUE) {
// The key has the correct value, so read in the FS-load elements and enter the bootloader.
mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR + 4, ELEM_DATA_SIZE, ELEM_DATA_START);
*initial_r0 = MBOOT_INITIAL_R0_KEY_FSLOAD;
reset_mode = BOARDCTRL_RESET_MODE_BOOTLOADER;
}
} else {
// Battery is not present. Cycle through reset modes until button is pressed.
systick_init();
hub_display_on();
reset_mode = 0;
for (int i = 0; i < (RESET_MODE_NUM_STATES * RESET_MODE_TIMEOUT_CYCLES + 1) * 64; i++) {
if (i % 64 == 0) {
if (++reset_mode > RESET_MODE_NUM_STATES) {
reset_mode = BOARDCTRL_RESET_MODE_NORMAL;
}
board_led_pattern(reset_mode, 0x7fff);
}
if (board_button_state()) {
break;
}
mp_hal_delay_ms(19);
}
// Flash the selected reset mode.
for (int i = 0; i < 6; i++) {
board_led_pattern(reset_mode, 0x0fff);
mp_hal_delay_ms(50);
board_led_pattern(reset_mode, 0x7fff);
mp_hal_delay_ms(50);
}
mp_hal_delay_ms(300);
}
board_led_pattern(0, 0);
return reset_mode;
}
void board_mboot_state_change(int state, uint32_t arg) {
if (state == MBOOT_STATE_FSLOAD_END) {
// The FS-load update completed (either with success or failure), so erase the
// update key and write the result of the FS-load operation into flash.
mp_spiflash_erase_block(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR);
mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR + 4, 4, (const uint8_t *)&arg);
}
mboot_state_change_default(state, arg);
}
#endif

6
ports/stm32/boards/LEGO_HUB_NO7/cc2564.c

@ -0,0 +1,6 @@
// LEGO_HUB_NO7 is nearly identical to LEGO_HUB_NO6 in this regard.
#define CC2564_TIMER_BT_SLOWCLOCK_TIM 2
#define CC2564_TIMER_BT_SLOWCLOCK_TIM_CH 2
#include "../LEGO_HUB_NO6/cc2564.c"

190
ports/stm32/boards/LEGO_HUB_NO7/hub_display.c

@ -0,0 +1,190 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Damien P. George
* Copyright (c) 2022 David Lechner <david@pybricks.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mphal.h"
#include "hub_display.h"
#include STM32_HAL_H
#define I2C_ADDR 0x28
// Registers
#define DEVICE_CONFIG0 0x00
#define DEVICE_CONFIG1 0x01
#define LED_CONFIG0 0x02
#define BANK_BRIGHTNESS 0x03
#define BANK_A_COLOR 0x04
#define BANK_B_COLOR 0x05
#define BANK_C_COLOR 0x06
#define LED0_BRIGHTNESS 0x07
#define LED1_BRIGHTNESS 0x08
#define LED2_BRIGHTNESS 0x09
#define LED3_BRIGHTNESS 0x0A
#define OUT0_COLOR 0x0B
#define OUT1_COLOR 0x0C
#define OUT2_COLOR 0x0D
#define OUT3_COLOR 0x0E
#define OUT4_COLOR 0x0F
#define OUT5_COLOR 0x10
#define OUT6_COLOR 0x11
#define OUT7_COLOR 0x12
#define OUT8_COLOR 0x13
#define OUT9_COLOR 0x14
#define OUT10_COLOR 0x15
#define OUT11_COLOR 0x16
#define RESET 0x17
// Flags
#define DEVICE_CONFIG0_CHIP_EN (1 << 6)
#define DEVICE_CONFIG1_LOG_SCALE_EN (1 << 5)
#define DEVICE_CONFIG1_POWER_SAVE_EN (1 << 4)
#define DEVICE_CONFIG1_AUTO_INCR_EN (1 << 3)
#define DEVICE_CONFIG1_PWM_DITHERING_EN (1 << 2)
#define DEVICE_CONFIG1_MAX_CURRENT_OPTION (1 << 1)
#define DEVICE_CONFIG1_LED_GLOBAL_OFF (1 << 0)
#define LED_CONFIG0_LED3_BANK_EN (1 << 3)
#define LED_CONFIG0_LED2_BANK_EN (1 << 2)
#define LED_CONFIG0_LED1_BANK_EN (1 << 1)
#define LED_CONFIG0_LED0_BANK_EN (1 << 0)
#define LP50XX_NUM_CH 6
// channel mapping:
// CH 0 = battery LED - red
// CH 1 = battery LED - green
// CH 2 = battery LED - blue
// CH 3 = status LED - red
// CH 4 = status LED - green
// CH 5 = status LED - blue
#define FMPI2C_CONVERT_TIMINGS(PRESC, SCLDEL, SDADEL, SCLH, SCLL) \
(((PRESC) << FMPI2C_TIMINGR_PRESC_Pos) | \
((SCLDEL) << FMPI2C_TIMINGR_SCLDEL_Pos) | \
((SDADEL) << FMPI2C_TIMINGR_SDADEL_Pos) | \
((SCLH) << FMPI2C_TIMINGR_SCLH_Pos) | \
((SCLL) << FMPI2C_TIMINGR_SCLL_Pos))
static FMPI2C_HandleTypeDef hub_display_i2c;
static bool hub_display_init;
static struct {
uint8_t reg;
uint8_t values[LP50XX_NUM_CH];
} __attribute__((packed)) hub_display_data = {
.reg = OUT0_COLOR,
};
void HAL_FMPI2C_MspInit(FMPI2C_HandleTypeDef *hfmpi2c) {
__HAL_RCC_FMPI2C1_CLK_ENABLE();
mp_hal_pin_config(pyb_pin_LED_SCL, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 4);
mp_hal_pin_config(pyb_pin_LED_SDA, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 4);
}
void HAL_FMPI2C_MspDeInit(FMPI2C_HandleTypeDef *hfmpi2c) {
__HAL_RCC_FMPI2C1_CLK_DISABLE();
__HAL_RCC_FMPI2C1_FORCE_RESET();
__HAL_RCC_FMPI2C1_RELEASE_RESET();
mp_hal_pin_config(pyb_pin_LED_SCL, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
mp_hal_pin_config(pyb_pin_LED_SDA, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
}
static void hub_display_i2c_init(void) {
hub_display_i2c.Instance = FMPI2C1;
hub_display_i2c.Init.Timing = FMPI2C_CONVERT_TIMINGS(0, 4, 0, 19, 28);
hub_display_i2c.Init.OwnAddress1 = 0;
hub_display_i2c.Init.AddressingMode = FMPI2C_ADDRESSINGMODE_7BIT;
hub_display_i2c.Init.DualAddressMode = FMPI2C_DUALADDRESS_DISABLE;
hub_display_i2c.Init.OwnAddress2 = 0;
hub_display_i2c.Init.OwnAddress2Masks = FMPI2C_OA2_NOMASK;
hub_display_i2c.Init.GeneralCallMode = FMPI2C_GENERALCALL_DISABLE;
hub_display_i2c.Init.NoStretchMode = FMPI2C_NOSTRETCH_DISABLE;
HAL_FMPI2C_Init(&hub_display_i2c);
}
void hub_display_set(uint8_t led, uint16_t value) {
if (led >= LP50XX_NUM_CH) {
return;
}
hub_display_data.values[led] = value >> 8;
}
void hub_display_update(void) {
if (!hub_display_init) {
return;
}
HAL_FMPI2C_Master_Transmit(&hub_display_i2c, I2C_ADDR, (uint8_t *)&hub_display_data,
sizeof(hub_display_data), HAL_MAX_DELAY);
}
void hub_display_on(void) {
if (hub_display_init) {
return;
}
hub_display_i2c_init();
mp_hal_pin_output(pyb_pin_LED_EN);
mp_hal_pin_high(pyb_pin_LED_EN);
static const struct {
uint8_t reg;
uint8_t values[11];
} __attribute__((packed)) init_data = {
.reg = DEVICE_CONFIG0,
.values = {
[DEVICE_CONFIG0] = DEVICE_CONFIG0_CHIP_EN,
[DEVICE_CONFIG1] = DEVICE_CONFIG1_POWER_SAVE_EN | DEVICE_CONFIG1_PWM_DITHERING_EN | DEVICE_CONFIG1_AUTO_INCR_EN,
[LED_CONFIG0] = 0,
[BANK_BRIGHTNESS] = 0,
[BANK_A_COLOR] = 0,
[BANK_B_COLOR] = 0,
[BANK_C_COLOR] = 0,
[LED0_BRIGHTNESS] = 51, // battery LED
[LED1_BRIGHTNESS] = 38, // status LED
[LED2_BRIGHTNESS] = 0,
[LED3_BRIGHTNESS] = 0,
}
};
HAL_FMPI2C_Master_Transmit(&hub_display_i2c, I2C_ADDR, (uint8_t *)&init_data,
sizeof(init_data), HAL_MAX_DELAY);
hub_display_init = true;
}
void hub_display_off(void) {
if (!hub_display_init) {
return;
}
HAL_FMPI2C_DeInit(&hub_display_i2c);
mp_hal_pin_config(pyb_pin_LED_EN, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0);
hub_display_init = false;
}

4
ports/stm32/boards/LEGO_HUB_NO7/hub_display.h

@ -0,0 +1,4 @@
void hub_display_on(void);
void hub_display_off(void);
void hub_display_update(void);
void hub_display_set(uint8_t led, uint16_t value);

5
ports/stm32/boards/LEGO_HUB_NO7/manifest.py

@ -0,0 +1,5 @@
include("$(PORT_DIR)/boards/manifest.py")
# Modules for application firmware update.
freeze("$(PORT_DIR)/mboot", "fwupdate.py", opt=3)
freeze("$(PORT_DIR)/boards/LEGO_HUB_NO6", ("spiflash.py", "appupdate.py"), opt=3)

152
ports/stm32/boards/LEGO_HUB_NO7/mpconfigboard.h

@ -0,0 +1,152 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
* The MIT License (MIT)
* Copyright (c) 2021 Damien P. George
*/
#include <stdint.h>
#define MICROPY_HW_BOARD_NAME "LEGO Technic Hub No.7"
#define MICROPY_HW_MCU_NAME "STM32F413"
#define MICROPY_HW_HAS_SWITCH (0)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_PY_PYB_LEGACY (0)
#define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (0)
#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_DAC (1)
#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_FLASH_FS_LABEL "HUB_NO7"
// HSE is 16MHz, CPU freq set to 100MHz, buses at maximum freq
#define MICROPY_HW_CLK_PLLM (16)
#define MICROPY_HW_CLK_PLLN (200)
#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2)
#define MICROPY_HW_CLK_PLLQ (4)
#define MICROPY_HW_CLK_AHB_DIV (RCC_SYSCLK_DIV1)
#define MICROPY_HW_CLK_APB1_DIV (RCC_HCLK_DIV2)
#define MICROPY_HW_CLK_APB2_DIV (RCC_HCLK_DIV1)
// For 2.7 to 3.6 V, 75 to 100 MHz: 3 wait states.
#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_3
// UART buses
// Bluetooth HCI
#define MICROPY_HW_UART2_CTS (pyb_pin_BT_CTS)
#define MICROPY_HW_UART2_RTS (pyb_pin_BT_RTS)
#define MICROPY_HW_UART2_TX (pyb_pin_BT_TX)
#define MICROPY_HW_UART2_RX (pyb_pin_BT_RX)
// Port B
#define MICROPY_HW_UART3_TX (pyb_pin_PORTB_TX)
#define MICROPY_HW_UART3_RX (pyb_pin_PORTB_RX)
// Port A
#define MICROPY_HW_UART5_TX (pyb_pin_PORTA_TX)
#define MICROPY_HW_UART5_RX (pyb_pin_PORTA_RX)
// SPI buses
#define MICROPY_HW_SPI2_NSS (pyb_pin_FLASH_NSS)
#define MICROPY_HW_SPI2_SCK (pyb_pin_FLASH_SCK)
#define MICROPY_HW_SPI2_MISO (pyb_pin_FLASH_MISO)
#define MICROPY_HW_SPI2_MOSI (pyb_pin_FLASH_MOSI)
// USB config
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pyb_pin_USB_VBUS)
#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_MSC (1)
// Bluetooth config
#define MICROPY_HW_BLE_UART_ID (PYB_UART_2)
#define MICROPY_HW_BLE_UART_BAUDRATE (115200)
#define MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY (921600)
#define MICROPY_HW_BLE_BTSTACK_CHIPSET_INSTANCE btstack_chipset_cc256x_instance()
// SPI flash, for R/W storage
// The first 1MiB is skipped because it's used by the built-in bootloader
// Note: MICROPY_HW_SPIFLASH_OFFSET_BYTES must be a multiple of MP_SPIFLASH_ERASE_BLOCK_SIZE
#define MICROPY_HW_SPIFLASH_OFFSET_BYTES (1024 * 1024)
#define MICROPY_HW_SPIFLASH_BLOCKMAP(bl) ((bl) + MICROPY_HW_SPIFLASH_OFFSET_BYTES / FLASH_BLOCK_SIZE)
#define MICROPY_HW_SPIFLASH_BLOCKMAP_EXT(bl) ((bl) + MICROPY_HW_SPIFLASH_OFFSET_BYTES / MP_SPIFLASH_ERASE_BLOCK_SIZE)
#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
#define MICROPY_HW_SPIFLASH_SIZE_BITS (32 * 1024 * 1024 - MICROPY_HW_SPIFLASH_OFFSET_BYTES * 8)
#define MICROPY_HW_SPIFLASH_CS (MICROPY_HW_SPI2_NSS)
#define MICROPY_HW_SPIFLASH_SCK (MICROPY_HW_SPI2_SCK)
#define MICROPY_HW_SPIFLASH_MISO (MICROPY_HW_SPI2_MISO)
#define MICROPY_HW_SPIFLASH_MOSI (MICROPY_HW_SPI2_MOSI)
// SPI flash, block device config
#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
(op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
(op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
spi_bdev_ioctl(&spi_bdev, (op), (arg)) \
)
// Configuration for stardard block protocol (block size FLASH_BLOCK_SIZE).
#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) \
spi_bdev_readblocks(&spi_bdev, (dest), MICROPY_HW_SPIFLASH_BLOCKMAP(bl), (n))
#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) \
spi_bdev_writeblocks(&spi_bdev, (src), MICROPY_HW_SPIFLASH_BLOCKMAP(bl), (n))
// Configuration for extended block protocol (block size MP_SPIFLASH_ERASE_BLOCK_SIZE).
#define MICROPY_HW_BDEV_BLOCKSIZE_EXT (MP_SPIFLASH_ERASE_BLOCK_SIZE)
#define MICROPY_HW_BDEV_READBLOCKS_EXT(dest, bl, off, len) \
(spi_bdev_readblocks_raw(&spi_bdev, (dest), MICROPY_HW_SPIFLASH_BLOCKMAP_EXT(bl), (off), (len)))
#define MICROPY_HW_BDEV_WRITEBLOCKS_EXT(src, bl, off, len) \
(spi_bdev_writeblocks_raw(&spi_bdev, (src), MICROPY_HW_SPIFLASH_BLOCKMAP_EXT(bl), (off), (len)))
#define MICROPY_HW_BDEV_ERASEBLOCKS_EXT(bl, len) \
(spi_bdev_eraseblocks_raw(&spi_bdev, MICROPY_HW_SPIFLASH_BLOCKMAP_EXT(bl), (len)))
// Board control config
#define MICROPY_BOARD_STARTUP board_init
/******************************************************************************/
// Bootloader configuration
// Configure CPU frequency to 96MHz, to make updates from SPI flash faster
#define MBOOT_CLK_PLLM (MICROPY_HW_CLK_VALUE / 1000000)
#define MBOOT_CLK_PLLN (192)
#define MBOOT_CLK_PLLP (RCC_PLLP_DIV2)
#define MBOOT_CLK_PLLQ (4)
#define MBOOT_CLK_AHB_DIV (RCC_SYSCLK_DIV1)
#define MBOOT_CLK_APB1_DIV (RCC_HCLK_DIV4)
#define MBOOT_CLK_APB2_DIV (RCC_HCLK_DIV2)
#define MBOOT_FLASH_LATENCY FLASH_LATENCY_3
#define MBOOT_FSLOAD (1)
#define MBOOT_VFS_FAT (1)
#define MBOOT_LEAVE_BOOTLOADER_VIA_RESET (0)
#define MBOOT_SPIFLASH_ADDR (0x80000000)
#define MBOOT_SPIFLASH_BYTE_SIZE (4 * 1024 * 1024)
#define MBOOT_SPIFLASH_LAYOUT "/0x80000000/1024*4Kg"
#define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (1)
#define MBOOT_SPIFLASH_SPIFLASH (&board_mboot_spiflash)
#define MBOOT_SPIFLASH_CONFIG (&board_mboot_spiflash_config)
#define MBOOT_LED1 0
#define MBOOT_LED2 1
#define MBOOT_LED3 2
#define MBOOT_BOARD_LED_INIT board_mboot_led_init
#define MBOOT_BOARD_LED_STATE board_mboot_led_state
#define MBOOT_BOARD_EARLY_INIT(initial_r0) board_init()
#define MBOOT_BOARD_CLEANUP board_mboot_cleanup
#define MBOOT_BOARD_GET_RESET_MODE board_mboot_get_reset_mode
#define MBOOT_BOARD_STATE_CHANGE board_mboot_state_change
/******************************************************************************/
// Function declarations
extern const struct _mp_spiflash_config_t spiflash_config;
extern struct _spi_bdev_t spi_bdev;
extern const struct _mp_spiflash_config_t board_mboot_spiflash_config;
extern struct _mp_spiflash_t board_mboot_spiflash;
void board_init(void);
void board_mboot_cleanup(int reset_mode);
void board_mboot_led_init(void);
void board_mboot_led_state(int led, int state);
int board_mboot_get_reset_mode(uint32_t *initial_r0);
void board_mboot_state_change(int state, uint32_t arg);
void *btstack_chipset_cc256x_instance(void);

50
ports/stm32/boards/LEGO_HUB_NO7/mpconfigboard.mk

@ -0,0 +1,50 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F413xx
AF_FILE = boards/stm32f413_af.csv
LD_FILES = boards/LEGO_HUB_NO6/stm32f413xg.ld boards/common_bl.ld
TEXT0_ADDR = 0x08010000
BOOTLOADER_DFU_USB_VID ?= 0x0694
BOOTLOADER_DFU_USB_PID ?= 0x000C
# MicroPython settings
MICROPY_PY_BLUETOOTH ?= 1
MICROPY_BLUETOOTH_NIMBLE ?= 0
MICROPY_BLUETOOTH_BTSTACK ?= 1
MICROPY_VFS_LFS2 ?= 1
# Board specific frozen modules
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
SRC_HAL += $(STM32LIB_HAL_BASE)/Src/stm32f4xx_hal_fmpi2c.c
ifneq ($(BUILDING_MBOOT),1)
LIB_SRC_C += lib/btstack/chipset/cc256x/btstack_chipset_cc256x.c
endif
# Bootloader settings
MBOOT_TEXT0_ADDR = 0x08008000
MBOOT_LD_FILES = ../boards/LEGO_HUB_NO6/mboot_memory.ld stm32_sections.ld
# Backup/restore original Hub firmware
HUB_FIRMWARE = lego_hub_firmware.dfu
HUB_FIRMWARE_ADDR = $(MBOOT_TEXT0_ADDR)
HUB_FIRMWARE_SIZE = 0xf8000
backup-hub-firmware:
$(Q)$(DFU_UTIL) -a 0 \
-d $(BOOTLOADER_DFU_USB_VID):$(BOOTLOADER_DFU_USB_PID) \
-U $(HUB_FIRMWARE).bin \
-s $(HUB_FIRMWARE_ADDR):$(HUB_FIRMWARE_SIZE)
$(Q)$(PYTHON) $(DFU) \
-b $(HUB_FIRMWARE_ADDR):$(HUB_FIRMWARE).bin \
-D $(BOOTLOADER_DFU_USB_VID):$(BOOTLOADER_DFU_USB_PID) \
$(HUB_FIRMWARE)
$(Q)$(RM) $(HUB_FIRMWARE).bin
$(ECHO) "Backup created in $(HUB_FIRMWARE)"
restore-hub-firmware:
$(Q)$(DFU_UTIL) -a 0 \
-d $(BOOTLOADER_DFU_USB_VID):$(BOOTLOADER_DFU_USB_PID) \
-D $(HUB_FIRMWARE)

114
ports/stm32/boards/LEGO_HUB_NO7/pins.csv

@ -0,0 +1,114 @@
BT_CTS,PA0
BT_RTS,PA1
BT_TX,PA2
BT_RX,PA3
,PA4
,PA5
BAT_VMON_ADC,PA6
BAT_IMON_ADC,PA7
LSM6_SCL,PA8
USB_VBUS,PA9
CHGMODE,PA10
USB_DM,PA11
USB_DP,PA12
,PA13
,PA14
,PA15
BAT_NTC,PB0
BAT_PWR_EN,PB1
BUTTON,PB2
BT_SLOWCLK,PB3
PORTB_M1,PB4
PORTB_M2,PB5
PORTA_M1,PB6
PORTA_M2,PB7
PORTB_EN,PB8
PORTA_EN,PB9
FLASH_SCK,PB10
,PB11
FLASH_NSS,PB12
LED_EN,PB13
LED_SDA,PB14
LED_SCL,PB15
,PC0
,PC1
FLASH_MISO,PC2
FLASH_MOSI,PC3
CHG_IMON_ADC,PC4
,PC5
CHGOK,PC6
PORT_3V3_EN,PC7
BT_ENABLE,PC8
LSM6_SDA,PC9
PORTB_TX,PC10
PORTB_RX,PC11
PORTA_TX,PC12
LSM6_INT1,PC13
,PC14
,PC15
,PD0
,PD1
PORTA_RX,PD2
,PD3
,PD4
,PD5
,PD6
,PD7
,PD8
,PD9
,PD10
,PD11
,PD12
,PD13
,PD14
,PD15
,PE0
,PE1
,PE2
,PE3
,PE4
,PE5
,PE6
,PE7
,PE8
,PE9
,PE10
,PE11
,PE12
,PE13
,PE14
,PE15
,PF0
,PF1
,PF2
,PF3
,PF4
,PF5
,PF6
,PF7
,PF8
,PF9
,PF10
,PF11
,PF12
,PF13
,PF14
,PF15
,PG0
,PG1
,PG2
,PG3
,PG4
,PG5
,PG6
,PG7
,PG8
,PG9
,PG10
,PG11
,PG12
,PG13
,PG14
,PG15
,PH0
,PH1
1 BT_CTS PA0
2 BT_RTS PA1
3 BT_TX PA2
4 BT_RX PA3
5 PA4
6 PA5
7 BAT_VMON_ADC PA6
8 BAT_IMON_ADC PA7
9 LSM6_SCL PA8
10 USB_VBUS PA9
11 CHGMODE PA10
12 USB_DM PA11
13 USB_DP PA12
14 PA13
15 PA14
16 PA15
17 BAT_NTC PB0
18 BAT_PWR_EN PB1
19 BUTTON PB2
20 BT_SLOWCLK PB3
21 PORTB_M1 PB4
22 PORTB_M2 PB5
23 PORTA_M1 PB6
24 PORTA_M2 PB7
25 PORTB_EN PB8
26 PORTA_EN PB9
27 FLASH_SCK PB10
28 PB11
29 FLASH_NSS PB12
30 LED_EN PB13
31 LED_SDA PB14
32 LED_SCL PB15
33 PC0
34 PC1
35 FLASH_MISO PC2
36 FLASH_MOSI PC3
37 CHG_IMON_ADC PC4
38 PC5
39 CHGOK PC6
40 PORT_3V3_EN PC7
41 BT_ENABLE PC8
42 LSM6_SDA PC9
43 PORTB_TX PC10
44 PORTB_RX PC11
45 PORTA_TX PC12
46 LSM6_INT1 PC13
47 PC14
48 PC15
49 PD0
50 PD1
51 PORTA_RX PD2
52 PD3
53 PD4
54 PD5
55 PD6
56 PD7
57 PD8
58 PD9
59 PD10
60 PD11
61 PD12
62 PD13
63 PD14
64 PD15
65 PE0
66 PE1
67 PE2
68 PE3
69 PE4
70 PE5
71 PE6
72 PE7
73 PE8
74 PE9
75 PE10
76 PE11
77 PE12
78 PE13
79 PE14
80 PE15
81 PF0
82 PF1
83 PF2
84 PF3
85 PF4
86 PF5
87 PF6
88 PF7
89 PF8
90 PF9
91 PF10
92 PF11
93 PF12
94 PF13
95 PF14
96 PF15
97 PG0
98 PG1
99 PG2
100 PG3
101 PG4
102 PG5
103 PG6
104 PG7
105 PG8
106 PG9
107 PG10
108 PG11
109 PG12
110 PG13
111 PG14
112 PG15
113 PH0
114 PH1

23
ports/stm32/boards/LEGO_HUB_NO7/stm32f4xx_hal_conf.h

@ -0,0 +1,23 @@
/* This file is part of the MicroPython project, http://micropython.org/
* The MIT License (MIT)
* Copyright (c) 2019 Damien P. George
*/
#ifndef MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
#define MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
#include "boards/stm32f4xx_hal_conf_base.h"
#include "stm32f4xx_hal_fmpi2c.h"
#define HAL_FMPI2C_MODULE_ENABLED
// Oscillator values in Hz
#define HSE_VALUE (16000000)
#define LSE_VALUE (32768)
#define EXTERNAL_CLOCK_VALUE (12288000)
// Oscillator timeouts in ms
#define HSE_STARTUP_TIMEOUT (100)
#define LSE_STARTUP_TIMEOUT (5000)
#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H
Loading…
Cancel
Save