Merge branch 'master' into circuitpython-nickzoic-716-pulseio-esp8266
This commit is contained in:
commit
972b03850f
@ -12,6 +12,7 @@ env:
|
||||
- TRAVIS_BOARD=feather_m0_rfm69
|
||||
- TRAVIS_BOARD=feather_m0_rfm9x
|
||||
- TRAVIS_BOARD=feather_m0_express
|
||||
- TRAVIS_BOARD=feather_m0_express_crickit
|
||||
- TRAVIS_BOARD=feather_m4_express
|
||||
- TRAVIS_BOARD=itsybitsy_m0_express
|
||||
- TRAVIS_BOARD=itsybitsy_m4_express
|
||||
|
@ -104,7 +104,7 @@ Differences from `MicroPython <https://github.com/micropython/micropython>`__
|
||||
CircuitPython:
|
||||
|
||||
- includes a ports for MicroChip SAMD21 (Commonly known as M0 in Adafruit
|
||||
product names and SAMD51 (M4).
|
||||
product names) and SAMD51 (M4).
|
||||
- supports only SAMD21, SAMD51, and ESP8266 ports. An nRF port is under
|
||||
development.
|
||||
- tracks MicroPython's releases (not master).
|
||||
|
72
main.c
72
main.c
@ -233,40 +233,7 @@ bool start_mp(safe_mode_t safe_mode) {
|
||||
}
|
||||
}
|
||||
|
||||
int __attribute__((used)) main(void) {
|
||||
// initialise the cpu and peripherals
|
||||
safe_mode_t safe_mode = port_init();
|
||||
|
||||
rgb_led_status_init();
|
||||
|
||||
// Stack limit should be less than real stack size, so we have a chance
|
||||
// to recover from limit hit. (Limit is measured in bytes.)
|
||||
mp_stack_ctrl_init();
|
||||
mp_stack_set_limit((char*)&_estack - (char*)&_ebss - 1024);
|
||||
|
||||
#if MICROPY_MAX_STACK_USAGE
|
||||
// _ezero (same as _ebss) is an int, so start 4 bytes above it.
|
||||
mp_stack_set_bottom(&_ezero + 1);
|
||||
mp_stack_fill_with_sentinel();
|
||||
#endif
|
||||
|
||||
// Create a new filesystem only if we're not in a safe mode.
|
||||
// A power brownout here could make it appear as if there's
|
||||
// no SPI flash filesystem, and we might erase the existing one.
|
||||
filesystem_init(safe_mode == NO_SAFE_MODE, false);
|
||||
|
||||
// Reset everything and prep MicroPython to run boot.py.
|
||||
reset_port();
|
||||
reset_board();
|
||||
reset_mp();
|
||||
|
||||
// Turn on autoreload by default but before boot.py in case it wants to change it.
|
||||
autoreload_enable();
|
||||
|
||||
// By default our internal flash is readonly to local python code and
|
||||
// writable over USB. Set it here so that boot.py can change it.
|
||||
filesystem_writable_by_python(false);
|
||||
|
||||
void run_boot_py(safe_mode_t safe_mode) {
|
||||
// If not in safe mode, run boot before initing USB and capture output in a
|
||||
// file.
|
||||
if (filesystem_present() && safe_mode == NO_SAFE_MODE && MP_STATE_VM(vfs_mount_table) != NULL) {
|
||||
@ -338,6 +305,43 @@ int __attribute__((used)) main(void) {
|
||||
reset_port();
|
||||
reset_mp();
|
||||
}
|
||||
}
|
||||
|
||||
int __attribute__((used)) main(void) {
|
||||
// initialise the cpu and peripherals
|
||||
safe_mode_t safe_mode = port_init();
|
||||
|
||||
rgb_led_status_init();
|
||||
|
||||
// Stack limit should be less than real stack size, so we have a chance
|
||||
// to recover from limit hit. (Limit is measured in bytes.)
|
||||
mp_stack_set_top((char*)&_estack);
|
||||
mp_stack_set_limit((char*)&_estack - (char*)&_ebss - 1024);
|
||||
|
||||
#if MICROPY_MAX_STACK_USAGE
|
||||
// _ezero (same as _ebss) is an int, so start 4 bytes above it.
|
||||
mp_stack_set_bottom(&_ezero + 1);
|
||||
mp_stack_fill_with_sentinel();
|
||||
#endif
|
||||
|
||||
// Create a new filesystem only if we're not in a safe mode.
|
||||
// A power brownout here could make it appear as if there's
|
||||
// no SPI flash filesystem, and we might erase the existing one.
|
||||
filesystem_init(safe_mode == NO_SAFE_MODE, false);
|
||||
|
||||
// Reset everything and prep MicroPython to run boot.py.
|
||||
reset_port();
|
||||
reset_board();
|
||||
reset_mp();
|
||||
|
||||
// Turn on autoreload by default but before boot.py in case it wants to change it.
|
||||
autoreload_enable();
|
||||
|
||||
// By default our internal flash is readonly to local python code and
|
||||
// writable over USB. Set it here so that boot.py can change it.
|
||||
filesystem_writable_by_python(false);
|
||||
|
||||
run_boot_py(safe_mode);
|
||||
|
||||
// Start serial and HID after giving boot.py a chance to tweak behavior.
|
||||
serial_init();
|
||||
|
@ -26,11 +26,19 @@
|
||||
#include "background.h"
|
||||
|
||||
#include "audio_dma.h"
|
||||
#include "tick.h"
|
||||
#include "usb.h"
|
||||
#include "usb_mass_storage.h"
|
||||
|
||||
volatile uint64_t last_finished_tick = 0;
|
||||
|
||||
void run_background_tasks(void) {
|
||||
audio_dma_background();
|
||||
usb_msc_background();
|
||||
usb_cdc_background();
|
||||
last_finished_tick = ticks_ms;
|
||||
}
|
||||
|
||||
bool background_tasks_ok(void) {
|
||||
return ticks_ms - last_finished_tick < 1000;
|
||||
}
|
||||
|
@ -27,6 +27,9 @@
|
||||
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
|
||||
#define MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void run_background_tasks(void);
|
||||
bool background_tasks_ok(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
|
||||
|
@ -47,15 +47,7 @@
|
||||
STATIC void samd_clock_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
samd_clock_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
mp_printf(print, "%q.%q.%s(", MP_QSTR_samd, MP_QSTR_clock, self->name);
|
||||
if (clock_get_enabled(self->type, self->index)) {
|
||||
mp_printf(print, "frequency=%u", clock_get_frequency(self->type, self->index));
|
||||
uint32_t calibration = clock_get_calibration(self->type, self->index);
|
||||
if (calibration) {
|
||||
mp_printf(print, ", calibration=%u", calibration);
|
||||
}
|
||||
}
|
||||
mp_printf(print, ")");
|
||||
mp_printf(print, "%q.%q.%q", MP_QSTR_samd, MP_QSTR_clock, self->name);
|
||||
}
|
||||
|
||||
//| .. attribute:: enabled
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
const char *name;
|
||||
qstr name;
|
||||
uint8_t type;
|
||||
uint8_t index;
|
||||
} samd_clock_obj_t;
|
||||
@ -39,7 +39,7 @@ typedef struct {
|
||||
#define CLOCK(_name, _type, _index) \
|
||||
const samd_clock_obj_t clock_ ## _name = { \
|
||||
{ &samd_clock_type }, \
|
||||
.name = #_name, \
|
||||
.name = MP_QSTR_ ## _name, \
|
||||
.type = _type, \
|
||||
.index = _index, \
|
||||
}
|
||||
@ -47,7 +47,7 @@ const samd_clock_obj_t clock_ ## _name = { \
|
||||
#define CLOCK_SOURCE(_name) \
|
||||
const samd_clock_obj_t clock_ ## _name = { \
|
||||
{ &samd_clock_type }, \
|
||||
.name = #_name, \
|
||||
.name = MP_QSTR_ ## _name, \
|
||||
.type = 0, \
|
||||
.index = GCLK_SOURCE_ ## _name, \
|
||||
}
|
||||
@ -55,7 +55,7 @@ const samd_clock_obj_t clock_ ## _name = { \
|
||||
#define CLOCK_GCLK(_name) \
|
||||
const samd_clock_obj_t clock_ ## _name = { \
|
||||
{ &samd_clock_type }, \
|
||||
.name = #_name, \
|
||||
.name = MP_QSTR_ ## _name, \
|
||||
.type = 1, \
|
||||
.index = _name ## _GCLK_ID, \
|
||||
}
|
||||
@ -63,7 +63,7 @@ const samd_clock_obj_t clock_ ## _name = { \
|
||||
#define CLOCK_GCLK_(_name, _extra) \
|
||||
const samd_clock_obj_t clock_ ## _name ## _ ## _extra = { \
|
||||
{ &samd_clock_type }, \
|
||||
.name = #_name "_" #_extra, \
|
||||
.name = MP_QSTR_ ## _name ## _ ## _extra, \
|
||||
.type = 1, \
|
||||
.index = _name ## _GCLK_ID_ ## _extra, \
|
||||
}
|
||||
|
@ -24,3 +24,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -68,3 +68,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PB09)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PB08)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -71,3 +71,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PB09)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PB08)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -22,3 +22,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -23,3 +23,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -58,3 +58,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
38
ports/atmel-samd/boards/feather_m0_express_crickit/board.c
Normal file
38
ports/atmel-samd/boards/feather_m0_express_crickit/board.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* 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 "boards/board.h"
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
bool board_requests_safe_mode(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void reset_board(void) {
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Express with Crickit libraries"
|
||||
#define MICROPY_HW_MCU_NAME "samd21g18"
|
||||
|
||||
#define MICROPY_HW_NEOPIXEL (&pin_PA06)
|
||||
|
||||
// Clock rates are off: Salae reads 12MHz which is the limit even though we set it to the safer 8MHz.
|
||||
#define SPI_FLASH_BAUDRATE (8000000)
|
||||
|
||||
#define SPI_FLASH_MOSI_PIN PIN_PA08
|
||||
#define SPI_FLASH_MISO_PIN PIN_PA14
|
||||
#define SPI_FLASH_SCK_PIN PIN_PA09
|
||||
#define SPI_FLASH_CS_PIN PIN_PA13
|
||||
#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PA08D_SERCOM2_PAD0
|
||||
#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PA14C_SERCOM2_PAD2
|
||||
#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PA09D_SERCOM2_PAD1
|
||||
#define SPI_FLASH_SERCOM SERCOM2
|
||||
#define SPI_FLASH_SERCOM_INDEX 2
|
||||
#define SPI_FLASH_MOSI_PAD 0
|
||||
#define SPI_FLASH_MISO_PAD 2
|
||||
#define SPI_FLASH_SCK_PAD 1
|
||||
// <o> Transmit Data Pinout
|
||||
// <0x0=>PAD[0,1]_DO_SCK
|
||||
// <0x1=>PAD[2,3]_DO_SCK
|
||||
// <0x2=>PAD[3,1]_DO_SCK
|
||||
// <0x3=>PAD[0,3]_DO_SCK
|
||||
#define SPI_FLASH_DOPO 0
|
||||
#define SPI_FLASH_DIPO 2 // same as MISO pad
|
||||
|
||||
// These are pins not to reset.
|
||||
#define MICROPY_PORT_A (PORT_PA06 | PORT_PA08 | PORT_PA09 | PORT_PA13 | PORT_PA14 | PORT_PA24 | PORT_PA25)
|
||||
#define MICROPY_PORT_B ( 0 )
|
||||
#define MICROPY_PORT_C ( 0 )
|
||||
|
||||
#include "external_flash/external_flash.h"
|
||||
|
||||
// If you change this, then make sure to update the linker scripts as well to
|
||||
// make sure you don't overwrite code.
|
||||
#define CIRCUITPY_INTERNAL_NVM_SIZE 256
|
||||
|
||||
#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE)
|
||||
|
||||
#include "external_flash/devices.h"
|
||||
|
||||
#define EXTERNAL_FLASH_DEVICE_COUNT 2
|
||||
#define EXTERNAL_FLASH_DEVICES S25FL216K, \
|
||||
GD25Q16C
|
||||
|
||||
#include "external_flash/external_flash.h"
|
||||
|
||||
#define BOARD_HAS_CRYSTAL 1
|
||||
|
||||
#define DEFAULT_I2C_BUS_SCL (&pin_PA23)
|
||||
#define DEFAULT_I2C_BUS_SDA (&pin_PA22)
|
||||
|
||||
#define DEFAULT_SPI_BUS_SCK (&pin_PB11)
|
||||
#define DEFAULT_SPI_BUS_MOSI (&pin_PB10)
|
||||
#define DEFAULT_SPI_BUS_MISO (&pin_PA12)
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
@ -0,0 +1,17 @@
|
||||
LD_FILE = boards/samd21x18-bootloader-external-flash.ld
|
||||
USB_VID = 0x239A
|
||||
USB_PID = 0x8023
|
||||
USB_PRODUCT = "Feather M0 Express"
|
||||
USB_MANUFACTURER = "Adafruit Industries LLC"
|
||||
|
||||
SPI_FLASH_FILESYSTEM = 1
|
||||
LONGINT_IMPL = MPZ
|
||||
|
||||
CHIP_VARIANT = SAMD21G18A
|
||||
CHIP_FAMILY = samd21
|
||||
|
||||
# Include these Python libraries in firmware.
|
||||
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice
|
||||
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Motor
|
||||
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel
|
||||
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_seesaw
|
33
ports/atmel-samd/boards/feather_m0_express_crickit/pins.c
Normal file
33
ports/atmel-samd/boards/feather_m0_express_crickit/pins.c
Normal file
@ -0,0 +1,33 @@
|
||||
#include "shared-bindings/board/__init__.h"
|
||||
|
||||
#include "board_busses.h"
|
||||
|
||||
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB09) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA04) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA05) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB02) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB11) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA11) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PA11) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PA10) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA22) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA23) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA15) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA20) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA07) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA18) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA16) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA19) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PA06) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
|
||||
};
|
||||
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
|
@ -23,3 +23,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -23,3 +23,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -57,3 +57,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -1,4 +1,4 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Feather M4 Express"
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M4 Express"
|
||||
#define MICROPY_HW_MCU_NAME "samd51j19"
|
||||
|
||||
#define CIRCUITPY_MCU_FAMILY samd51
|
||||
@ -43,3 +43,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PB17)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PB16)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -40,6 +40,9 @@
|
||||
#define IGNORE_PIN_PA20 1
|
||||
#define IGNORE_PIN_PA21 1
|
||||
#define IGNORE_PIN_PA22 1
|
||||
// USB is always used.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
#define IGNORE_PIN_PA27 1
|
||||
#define IGNORE_PIN_PA28 1
|
||||
#define IGNORE_PIN_PA30 1
|
||||
|
@ -1,4 +1,4 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Itsy Bitsy M0 Express"
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit ItsyBitsy M0 Express"
|
||||
#define MICROPY_HW_MCU_NAME "samd21g18"
|
||||
|
||||
#define CIRCUITPY_BITBANG_APA102
|
||||
@ -56,3 +56,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -1,7 +1,7 @@
|
||||
LD_FILE = boards/samd21x18-bootloader-external-flash-crystalless.ld
|
||||
USB_VID = 0x239A
|
||||
USB_PID = 0x8012
|
||||
USB_PRODUCT = "Itsy Bitsy M0 Express"
|
||||
USB_PRODUCT = "ItsyBitsy M0 Express"
|
||||
USB_MANUFACTURER = "Adafruit Industries LLC"
|
||||
|
||||
SPI_FLASH_FILESYSTEM = 1
|
||||
|
@ -1,4 +1,4 @@
|
||||
#define MICROPY_HW_BOARD_NAME "ItsyBitsy M4 Express"
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit ItsyBitsy M4 Express"
|
||||
#define MICROPY_HW_MCU_NAME "samd51g19"
|
||||
|
||||
#define CIRCUITPY_MCU_FAMILY samd51
|
||||
@ -41,3 +41,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA16)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA17)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -59,3 +59,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA11)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA10)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -1,4 +1,4 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Metro M4 Express"
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Metro M4 Express"
|
||||
#define MICROPY_HW_MCU_NAME "samd51j19"
|
||||
|
||||
#define CIRCUITPY_MCU_FAMILY samd51
|
||||
@ -44,3 +44,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA23)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA22)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -30,6 +30,9 @@
|
||||
#define IGNORE_PIN_PA21 1
|
||||
#define IGNORE_PIN_PA22 1
|
||||
#define IGNORE_PIN_PA23 1
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
#define IGNORE_PIN_PA27 1
|
||||
#define IGNORE_PIN_PA28 1
|
||||
#define IGNORE_PIN_PA30 1
|
||||
|
@ -64,3 +64,7 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_PA07)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_PA06)
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -52,3 +52,7 @@
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module }
|
||||
|
||||
// USB is always used internally so skip the pin objects for it.
|
||||
#define IGNORE_PIN_PA24 1
|
||||
#define IGNORE_PIN_PA25 1
|
||||
|
@ -392,7 +392,18 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se
|
||||
break;
|
||||
}
|
||||
// Wait for the next buffer to fill
|
||||
uint32_t wait_counts = 0;
|
||||
#ifdef SAMD21
|
||||
#define MAX_WAIT_COUNTS 1000
|
||||
#endif
|
||||
#ifdef SAMD51
|
||||
#define MAX_WAIT_COUNTS 6000
|
||||
#endif
|
||||
while (!event_interrupt_active(event_channel)) {
|
||||
if (wait_counts++ > MAX_WAIT_COUNTS) {
|
||||
// Buffer has stopped filling; DMA may have missed an I2S trigger event.
|
||||
break;
|
||||
}
|
||||
#ifdef MICROPY_VM_HOOK_LOOP
|
||||
MICROPY_VM_HOOK_LOOP
|
||||
#endif
|
||||
|
@ -40,18 +40,10 @@ void common_hal_mcu_delay_us(uint32_t delay) {
|
||||
mp_hal_delay_us(delay);
|
||||
}
|
||||
|
||||
// Interrupt flags that will be saved and restored during disable/Enable
|
||||
// interrupt functions below.
|
||||
|
||||
// ASF4's interrupt disable doesn't handle duplicate calls
|
||||
volatile uint32_t interrupt_flags;
|
||||
volatile uint32_t nesting_count = 0;
|
||||
void common_hal_mcu_disable_interrupts(void) {
|
||||
if (nesting_count == 0) {
|
||||
interrupt_flags = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
__DMB();
|
||||
}
|
||||
__disable_irq();
|
||||
__DMB();
|
||||
nesting_count++;
|
||||
}
|
||||
|
||||
@ -66,7 +58,7 @@ void common_hal_mcu_enable_interrupts(void) {
|
||||
return;
|
||||
}
|
||||
__DMB();
|
||||
__set_PRIMASK(interrupt_flags);
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
extern uint32_t _ezero;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "atmel_start_pins.h"
|
||||
#include "hal/include/hal_gpio.h"
|
||||
|
||||
#include "background.h"
|
||||
#include "mpconfigport.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/runtime.h"
|
||||
@ -60,10 +61,16 @@ void pulsein_interrupt_handler(uint8_t channel) {
|
||||
uint32_t current_us;
|
||||
uint64_t current_ms;
|
||||
current_tick(¤t_ms, ¤t_us);
|
||||
|
||||
// current_tick gives us the remaining us until the next tick but we want the number since the
|
||||
// last ms.
|
||||
current_us = 1000 - current_us;
|
||||
pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
|
||||
if (!background_tasks_ok() || self->errored_too_fast) {
|
||||
self->errored_too_fast = true;
|
||||
common_hal_pulseio_pulsein_pause(self);
|
||||
return;
|
||||
}
|
||||
if (self->first_edge) {
|
||||
self->first_edge = false;
|
||||
pulsein_set_config(self, false);
|
||||
@ -118,6 +125,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self,
|
||||
self->first_edge = true;
|
||||
self->last_us = 0;
|
||||
self->last_ms = 0;
|
||||
self->errored_too_fast = false;
|
||||
|
||||
set_eic_channel_data(pin->extint_channel, (void*) self);
|
||||
|
||||
@ -157,6 +165,9 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self,
|
||||
// Make sure we're paused.
|
||||
common_hal_pulseio_pulsein_pause(self);
|
||||
|
||||
// Reset erroring
|
||||
self->errored_too_fast = false;
|
||||
|
||||
// Send the trigger pulse.
|
||||
if (trigger_duration > 0) {
|
||||
gpio_set_pin_pull_mode(self->pin, GPIO_PULL_OFF);
|
||||
@ -207,6 +218,11 @@ uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) {
|
||||
return self->len;
|
||||
}
|
||||
|
||||
bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self) {
|
||||
uint32_t mask = 1 << self->channel;
|
||||
return (EIC->INTENSET.reg & (mask << EIC_INTENSET_EXTINT_Pos)) == 0;
|
||||
}
|
||||
|
||||
uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self,
|
||||
int16_t index) {
|
||||
common_hal_mcu_disable_interrupts();
|
||||
|
@ -43,6 +43,7 @@ typedef struct {
|
||||
volatile bool first_edge;
|
||||
volatile uint64_t last_ms;
|
||||
volatile uint16_t last_us;
|
||||
volatile bool errored_too_fast;
|
||||
} pulseio_pulsein_obj_t;
|
||||
|
||||
void pulsein_reset(void);
|
||||
|
@ -130,6 +130,9 @@ static void init_clock_source_dfll48m_xosc(void) {
|
||||
SYSCTRL_DFLLCTRL_ENABLE;
|
||||
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
|
||||
// Wait for the fine lock on the DFLL.
|
||||
while (!SYSCTRL->PCLKSR.bit.DFLLLCKC || !SYSCTRL->PCLKSR.bit.DFLLLCKF) {}
|
||||
}
|
||||
|
||||
static void init_clock_source_dfll48m_usb(void) {
|
||||
|
@ -60,6 +60,22 @@ void tick_init() {
|
||||
uint32_t ticks_per_ms = common_hal_mcu_processor_get_frequency() / 1000;
|
||||
SysTick_Config(ticks_per_ms-1);
|
||||
NVIC_EnableIRQ(SysTick_IRQn);
|
||||
// Set all peripheral interrupt priorities to the lowest priority by default.
|
||||
for (uint16_t i = 0; i < PERIPH_COUNT_IRQn; i++) {
|
||||
NVIC_SetPriority(i, (1UL << __NVIC_PRIO_BITS) - 1UL);
|
||||
}
|
||||
// Bump up the systick interrupt.
|
||||
NVIC_SetPriority(SysTick_IRQn, 1);
|
||||
#ifdef SAMD21
|
||||
NVIC_SetPriority(USB_IRQn, 1);
|
||||
#endif
|
||||
|
||||
#ifdef SAMD51
|
||||
NVIC_SetPriority(USB_0_IRQn, 1);
|
||||
NVIC_SetPriority(USB_1_IRQn, 1);
|
||||
NVIC_SetPriority(USB_2_IRQn, 1);
|
||||
NVIC_SetPriority(USB_3_IRQn, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tick_delay(uint32_t us) {
|
||||
|
@ -71,6 +71,10 @@ uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self) {
|
||||
return 0xadaf;
|
||||
}
|
||||
|
||||
bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) {
|
||||
return 0xadaf;
|
||||
}
|
||||
|
@ -219,6 +219,26 @@ const mp_obj_property_t pulseio_pulsein_maxlen_obj = {
|
||||
(mp_obj_t)&mp_const_none_obj},
|
||||
};
|
||||
|
||||
//| .. attribute:: paused
|
||||
//|
|
||||
//| True when pulse capture is paused as a result of :py:func:`pause` or an error during capture
|
||||
//| such as a signal that is too fast.
|
||||
//|
|
||||
STATIC mp_obj_t pulseio_pulsein_obj_get_paused(mp_obj_t self_in) {
|
||||
pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self));
|
||||
|
||||
return mp_obj_new_bool(common_hal_pulseio_pulsein_get_paused(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_get_paused_obj, pulseio_pulsein_obj_get_paused);
|
||||
|
||||
const mp_obj_property_t pulseio_pulsein_paused_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&pulseio_pulsein_get_paused_obj,
|
||||
(mp_obj_t)&mp_const_none_obj,
|
||||
(mp_obj_t)&mp_const_none_obj},
|
||||
};
|
||||
|
||||
//| .. method:: __len__()
|
||||
//|
|
||||
//| Returns the current pulse length
|
||||
@ -285,7 +305,10 @@ STATIC const mp_rom_map_elem_t pulseio_pulsein_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&pulseio_pulsein_resume_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&pulseio_pulsein_clear_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&pulseio_pulsein_popleft_obj) },
|
||||
|
||||
// Properties
|
||||
{ MP_ROM_QSTR(MP_QSTR_maxlen), MP_ROM_PTR(&pulseio_pulsein_maxlen_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&pulseio_pulsein_paused_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pulseio_pulsein_locals_dict, pulseio_pulsein_locals_dict_table);
|
||||
|
||||
|
@ -41,6 +41,7 @@ extern void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, uint1
|
||||
extern void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self);
|
||||
extern uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self);
|
||||
extern uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self);
|
||||
extern bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self);
|
||||
extern uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self);
|
||||
extern uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, int16_t index);
|
||||
|
||||
|
@ -50,19 +50,19 @@
|
||||
//| :param ~microcontroller.Pin pin_a: First pin to read pulses from.
|
||||
//| :param ~microcontroller.Pin pin_b: Second pin to read pulses from.
|
||||
//|
|
||||
//| For example::
|
||||
//| For example::
|
||||
//|
|
||||
//| import rotaryio
|
||||
//| import time
|
||||
//| from board import *
|
||||
//| import rotaryio
|
||||
//| import time
|
||||
//| from board import *
|
||||
//|
|
||||
//| enc = rotaryio.IncrementalEncoder(D1, D2)
|
||||
//| last_position = None
|
||||
//| while True;
|
||||
//| position = enc.position
|
||||
//| if last_position == None or position != last_position:
|
||||
//| print(position)
|
||||
//| last_position = position
|
||||
//| enc = rotaryio.IncrementalEncoder(D1, D2)
|
||||
//| last_position = None
|
||||
//| while True:
|
||||
//| position = enc.position
|
||||
//| if last_position == None or position != last_position:
|
||||
//| print(position)
|
||||
//| last_position = position
|
||||
//|
|
||||
STATIC mp_obj_t rotaryio_incrementalencoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
|
||||
mp_arg_check_num(n_args, n_kw, 2, 2, true);
|
||||
|
@ -2,7 +2,7 @@ rm -rf ports/atmel-samd/build*
|
||||
rm -rf ports/esp8266/build*
|
||||
rm -rf ports/nrf/build*
|
||||
|
||||
ATMEL_BOARDS="arduino_zero circuitplayground_express circuitplayground_express_crickit feather_m0_basic feather_m0_adalogger itsybitsy_m0_express itsybitsy_m4_express feather_m0_rfm69 feather_m0_rfm9x feather_m0_express feather_m4_express metro_m0_express metro_m4_express pirkey_m0 trinket_m0 gemma_m0 feather52"
|
||||
ATMEL_BOARDS="arduino_zero circuitplayground_express circuitplayground_express_crickit feather_m0_basic feather_m0_adalogger itsybitsy_m0_express itsybitsy_m4_express feather_m0_rfm69 feather_m0_rfm9x feather_m0_express feather_m0_express_crickit feather_m4_express metro_m0_express metro_m4_express pirkey_m0 trinket_m0 gemma_m0 feather52"
|
||||
ROSIE_SETUPS="rosie-ci"
|
||||
|
||||
PARALLEL="-j 5"
|
||||
|
454
tools/chart_code_size.py
Normal file
454
tools/chart_code_size.py
Normal file
@ -0,0 +1,454 @@
|
||||
# This script renders a graph of the CircuitPython rom image.
|
||||
# It takes the single elf file and uses objdump to get its contents.
|
||||
|
||||
import pygraphviz as pgv
|
||||
import click
|
||||
import sh
|
||||
|
||||
# Replace dashes with underscores
|
||||
objdump = sh.arm_none_eabi_objdump
|
||||
|
||||
def parse_hex(h):
|
||||
return int("0x" + h, 0)
|
||||
|
||||
BAD_JUMPS = ["UNPREDICTABLE", "_etext"]
|
||||
|
||||
SPECIAL_NODE_COLORS = {
|
||||
"main": "pink",
|
||||
"exception_table": "green"
|
||||
}
|
||||
|
||||
@click.command()
|
||||
@click.argument("elf_filename")
|
||||
def do_all_the_things(elf_filename):
|
||||
symbol = None
|
||||
last_address = 0
|
||||
all_symbols = {}
|
||||
symbols_by_debug_address = {}
|
||||
symbols_by_memory_address = {}
|
||||
symbols_by_linkage_name = {}
|
||||
# Gather type info so we know how to treat the disassembly
|
||||
debug_dump = objdump("--dwarf=info", elf_filename)
|
||||
debug_dump_lines = debug_dump.stdout.decode("utf-8").split("\n")
|
||||
symbol_stack = []
|
||||
symbol = None
|
||||
ignore = False
|
||||
min_call_site_param = 0x20000000
|
||||
for line in debug_dump_lines:
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split()
|
||||
if line[1] == "<":
|
||||
if parts[-1] == "0":
|
||||
symbol = symbol_stack.pop()
|
||||
continue
|
||||
debug_type = parts[-1].strip("()")
|
||||
ignore = False
|
||||
# skip info about function parameters
|
||||
if debug_type == "DW_TAG_formal_parameter":
|
||||
ignore = True
|
||||
depth = int(parts[0].split(">")[0].strip("<"))
|
||||
if len(symbol_stack) == (depth - 1) and depth > 0:
|
||||
symbol_stack.append(symbol)
|
||||
elif symbol and "name" in symbol:
|
||||
if symbol["debug_type"] == "DW_TAG_variable":
|
||||
if "start_address" not in symbol:
|
||||
pass
|
||||
else:
|
||||
symbols_by_memory_address[symbol["start_address"]] = symbol
|
||||
elif symbol["debug_type"] in ["DW_TAG_member", "DW_TAG_label", "DW_TAG_typedef", "DW_TAG_enumerator", "DW_TAG_enumeration_type", "DW_TAG_base_type", "DW_TAG_structure_type", "DW_TAG_compile_unit", "DW_TAG_union_type"]:
|
||||
# skip symbols that don't end up in memory. the type info is available through the debug address map
|
||||
pass
|
||||
else:
|
||||
if symbol["name"] in all_symbols:
|
||||
# print(depth, symbol["name"])
|
||||
# print(symbol)
|
||||
# print(all_symbols[symbol["name"]])
|
||||
# print()
|
||||
pass
|
||||
all_symbols[symbol["name"]] = symbol
|
||||
elif symbol and symbol["debug_type"] == "DW_TAG_GNU_call_site_parameter" and "call_site_value" in symbol:
|
||||
parent = -1
|
||||
while symbol_stack[parent]["debug_type"] != "DW_TAG_subprogram":
|
||||
parent -= 1
|
||||
parent = symbol_stack[parent]
|
||||
|
||||
# Only point to ROM
|
||||
addr = symbol["call_site_value"]
|
||||
if 0x2000 <= addr < 0x20000000:
|
||||
if "outgoing_pointers" not in parent:
|
||||
parent["outgoing_pointers"] = set()
|
||||
parent["outgoing_pointers"].add(addr)
|
||||
if addr not in symbols_by_memory_address:
|
||||
symbols_by_memory_address[addr] = symbol
|
||||
min_call_site_param = min(addr, min_call_site_param)
|
||||
symbol["name"] = "name{:x}".format(addr)
|
||||
address = parse_hex(parts[0].split("<")[-1].strip(">:"))
|
||||
symbol = {"debug_address": address, "debug_type": debug_type, "other": []}
|
||||
if debug_type == "DW_TAG_structure_type":
|
||||
symbol["struct"] = {}
|
||||
elif debug_type == "DW_TAG_array_type":
|
||||
symbol["subtype"] = None
|
||||
symbol["bound_count"] = 0
|
||||
symbol["maxlen"] = 0
|
||||
elif debug_type == "DW_TAG_subrange_type":
|
||||
symbol_stack[-1]["subtype"] = symbol
|
||||
symbols_by_debug_address[address] = symbol
|
||||
elif ignore:
|
||||
continue
|
||||
elif line[:4] == " ":
|
||||
tag = parts[1].strip(":")
|
||||
if tag == "DW_AT_name":
|
||||
symbol["name"] = parts[-1]
|
||||
elif tag == "DW_AT_type":
|
||||
symbol["type"] = int(parts[-1].strip("<>"), 0)
|
||||
if symbol["debug_type"] == "DW_TAG_subrange_type":
|
||||
if not symbol_stack[-1]["subtype"]:
|
||||
symbol_stack[-1]["subtype"] = symbol
|
||||
elif symbol_stack[-1]["subtype"]["type"] == symbol["type"]:
|
||||
second_subtype = True
|
||||
else:
|
||||
raise RuntimeError()
|
||||
elif tag == "DW_AT_upper_bound":
|
||||
# Skip arrays with length defined by other variables
|
||||
if parts[-1][0] != "<":
|
||||
upper_bound = int(parts[-1])
|
||||
if symbol_stack[-1]["bound_count"] > 0:
|
||||
symbol_stack[-1]["maxlen"] *= upper_bound + 1
|
||||
else:
|
||||
symbol_stack[-1]["maxlen"] = upper_bound + 1
|
||||
symbol_stack[-1]["bound_count"] += 1
|
||||
elif tag == "DW_AT_byte_size":
|
||||
symbol["size"] = int(parts[-1])
|
||||
elif tag == "DW_AT_inline":
|
||||
symbol["inlined"] = True
|
||||
elif tag == "DW_AT_low_pc":
|
||||
addr = int(parts[-1], 0)
|
||||
symbols_by_memory_address[addr] = symbol
|
||||
elif tag == "DW_AT_location":
|
||||
if parts[-2] == "(DW_OP_addr:":
|
||||
addr = parse_hex(parts[-1].strip(")"))
|
||||
if addr > 0:
|
||||
symbol["start_address"] = addr
|
||||
elif tag == "DW_AT_linkage_name":
|
||||
symbol["linkage_name"] = parts[-1]
|
||||
symbols_by_linkage_name[symbol["linkage_name"]] = symbol
|
||||
elif tag == "DW_AT_data_member_location":
|
||||
symbol_stack[-1]["struct"][int(parts[-1])] = symbol
|
||||
elif tag == "DW_AT_GNU_call_site_value":
|
||||
if parts[-2] == "(DW_OP_addr:":
|
||||
symbol["call_site_value"] = parse_hex(parts[-1].strip(")"))
|
||||
else:
|
||||
symbol["other"].append(line)
|
||||
#print(parts)
|
||||
pass
|
||||
else:
|
||||
#print(line)
|
||||
pass
|
||||
|
||||
MEMORY_NONE = 0
|
||||
MEMORY_POINTER = 1
|
||||
MEMORY_PY_OBJECT = 2
|
||||
|
||||
def get_size(t):
|
||||
if "size" in t:
|
||||
return t["size"]
|
||||
return get_size(symbols_by_debug_address[t["type"]])
|
||||
|
||||
def get_pointer_map(t, depth=0):
|
||||
if t["debug_type"] == "DW_TAG_pointer_type":
|
||||
return {0: MEMORY_POINTER}
|
||||
elif t["debug_type"] in ["DW_TAG_const_type", "DW_TAG_typedef", "DW_TAG_member", "DW_TAG_subrange_type", "DW_TAG_volatile_type"]:
|
||||
if "name" in t and t["name"] == "mp_rom_obj_t":
|
||||
return {0: MEMORY_PY_OBJECT}
|
||||
return get_pointer_map(symbols_by_debug_address[t["type"]], depth+1)
|
||||
elif t["debug_type"] in ["DW_TAG_base_type", "DW_TAG_enumeration_type"]:
|
||||
return {}
|
||||
elif t["debug_type"] == "DW_TAG_union_type":
|
||||
# skip for now
|
||||
return {}
|
||||
elif "struct" in t:
|
||||
combined_map = {}
|
||||
for offset in t["struct"]:
|
||||
member = t["struct"][offset]
|
||||
submap = get_pointer_map(member)
|
||||
for suboffset in submap:
|
||||
combined_map[offset + suboffset] = submap[suboffset]
|
||||
return combined_map
|
||||
elif "subtype" in t:
|
||||
subtype = symbols_by_debug_address[t["type"]]
|
||||
pmap = get_pointer_map(subtype, depth+1)
|
||||
size = get_size(subtype)
|
||||
expanded_map = {}
|
||||
for i in range(t["maxlen"]):
|
||||
for offset in pmap:
|
||||
expanded_map[size * i + offset] = pmap[offset]
|
||||
return expanded_map
|
||||
else:
|
||||
print("no recurse", t)
|
||||
pass
|
||||
return {}
|
||||
|
||||
# Do a second pass to dereference the types
|
||||
for symbol_address in symbols_by_memory_address:
|
||||
symbol = symbols_by_memory_address[symbol_address]
|
||||
if "type" in symbol:
|
||||
if symbol["debug_type"] == "DW_TAG_variable":
|
||||
symbol["pointer_map"] = get_pointer_map(symbols_by_debug_address[symbol["type"]])
|
||||
type_string = []
|
||||
t = symbol["type"]
|
||||
offset = []
|
||||
while t != None:
|
||||
t_symbol = symbols_by_debug_address[t]
|
||||
t = t_symbol.get("type", None)
|
||||
if "name" in t_symbol:
|
||||
type_string.append(t_symbol["name"])
|
||||
elif t_symbol["debug_type"] == "DW_TAG_array_type":
|
||||
type_string.append("[]")
|
||||
elif t_symbol["debug_type"] == "DW_TAG_pointer_type":
|
||||
type_string.append("*")
|
||||
elif t_symbol["debug_type"] == "DW_TAG_const_type":
|
||||
type_string.append("const")
|
||||
elif t_symbol["debug_type"] == "DW_TAG_volatile_type":
|
||||
type_string.append("volatile")
|
||||
else:
|
||||
#print(" ", t_symbol)
|
||||
pass
|
||||
type_string.reverse()
|
||||
symbol["type_string"] = " ".join(type_string)
|
||||
#print(symbol_name, symbol["debug_type"], symbol.get("type_string", ""))
|
||||
|
||||
# print()
|
||||
# print()
|
||||
# print(all_symbols["mp_builtin_module_table"])
|
||||
# return
|
||||
|
||||
# Gather size and call info
|
||||
text_dump = objdump("-Dz", "-j", ".text", elf_filename)
|
||||
text_dump_lines = text_dump.stdout.decode("utf-8").split("\n")
|
||||
section = None
|
||||
symbol = None
|
||||
symbol_type = None
|
||||
for line in text_dump_lines[4:]:
|
||||
if line.startswith("Disassembly of section"):
|
||||
section = line.split()[-1].strip(":")
|
||||
elif not line:
|
||||
if symbol and "end_address" not in symbol:
|
||||
symbol["end_address"] = last_address
|
||||
symbol["size"] = last_address - symbol["start_address"]
|
||||
symbol = None
|
||||
continue
|
||||
elif line[0].isnumeric():
|
||||
symbol_address, symbol_name = line.split()
|
||||
symbol_address = parse_hex(symbol_address)
|
||||
symbol_name = symbol_name.strip("<>:")
|
||||
if symbol_name in symbols_by_linkage_name:
|
||||
linked_name = symbol_name
|
||||
symbol = symbols_by_linkage_name[symbol_name]
|
||||
if "name" in symbol:
|
||||
non_linkage = symbol["name"]
|
||||
if not non_linkage.startswith("__builtin"):
|
||||
symbol_name = non_linkage
|
||||
all_symbols[symbol_name] = symbol
|
||||
if "name" not in symbol:
|
||||
symbol["name"] = symbol_name
|
||||
elif symbol_address in symbols_by_memory_address:
|
||||
all_symbols[symbol_name] = symbols_by_memory_address[symbol_address]
|
||||
if "name" not in all_symbols[symbol_name]:
|
||||
all_symbols[symbol_name]["name"] = symbol_name
|
||||
elif symbol_name not in all_symbols:
|
||||
if symbol_name == "nlr_push_tail_var":
|
||||
fake_type = all_symbols["mp_obj_get_type"]["type"]
|
||||
symbol = {"debug_type": "DW_TAG_variable", "name": symbol_name, "type": fake_type}
|
||||
else:
|
||||
print(line)
|
||||
print(symbol_name, symbol_address)
|
||||
symbol = {"debug_type": "DW_TAG_subprogram", "name": symbol_name}
|
||||
all_symbols[symbol_name] = symbol
|
||||
#raise RuntimeError()
|
||||
|
||||
symbol = all_symbols[symbol_name]
|
||||
symbol["start_address"] = symbol_address
|
||||
symbols_by_memory_address[symbol_address] = symbol
|
||||
symbol["section"] = section
|
||||
|
||||
if symbol["debug_type"] == "DW_TAG_subprogram":
|
||||
symbol["outgoing_jumps"] = set()
|
||||
symbol["incoming_jumps"] = set()
|
||||
symbol_type = None
|
||||
elif symbol["debug_type"] == "DW_TAG_variable":
|
||||
symbol["outgoing_pointers"] = set()
|
||||
symbol_type = symbols_by_debug_address[symbol["type"]]
|
||||
all_symbols[symbol_name] = symbol
|
||||
|
||||
elif line[0] == " ":
|
||||
parts = line.strip().split()
|
||||
last_address = parse_hex(parts[0].strip(":"))
|
||||
|
||||
offset = last_address - symbol["start_address"]
|
||||
if "pointer_map" in symbol:
|
||||
if offset not in symbol["pointer_map"]:
|
||||
#print(offset, symbol)
|
||||
pass
|
||||
else:
|
||||
ref = parse_hex(parts[1])
|
||||
pointer_style = symbol["pointer_map"][offset]
|
||||
if pointer_style == MEMORY_POINTER:
|
||||
symbol["outgoing_pointers"].add(ref & 0xfffffffe)
|
||||
elif pointer_style == MEMORY_PY_OBJECT and ref & 0x3 == 0:
|
||||
symbol["outgoing_pointers"].add(ref)
|
||||
if len(parts[1]) == 8 and parts[1][0] == "0":
|
||||
addr = parse_hex(parts[1])
|
||||
if 0x2000 <= addr < 0x20000000:
|
||||
if "outgoing_pointers" not in symbol:
|
||||
symbol["outgoing_pointers"] = set()
|
||||
symbol["outgoing_pointers"].add(addr)
|
||||
elif "<" in line and symbol["debug_type"] == "DW_TAG_subprogram":
|
||||
if line[-1] == ">":
|
||||
jump_to = parts[-1].strip("<>").split("+")[0]
|
||||
if "name" not in symbol:
|
||||
print(jump_to)
|
||||
print(symbol)
|
||||
if jump_to != symbol["name"] and jump_to not in BAD_JUMPS:
|
||||
symbol["outgoing_jumps"].add(jump_to)
|
||||
#print(symbol_name, jump_to)
|
||||
if jump_to == "_etext":
|
||||
print(line)
|
||||
elif "UNDEFINED" in line:
|
||||
continue
|
||||
elif parts[2] == "ldr":
|
||||
continue
|
||||
else:
|
||||
print(line)
|
||||
else:
|
||||
#print(line)
|
||||
pass
|
||||
|
||||
# print()
|
||||
print(hex(min_call_site_param))
|
||||
print(all_symbols["exception_table"])
|
||||
# return
|
||||
|
||||
print("converting outgoing pointers to names")
|
||||
|
||||
# Convert outgoing pointers to names from addresses
|
||||
for symbol_name in all_symbols:
|
||||
symbol = all_symbols[symbol_name]
|
||||
if "outgoing_pointers" not in symbol:
|
||||
continue
|
||||
converted = set()
|
||||
for outgoing in symbol["outgoing_pointers"]:
|
||||
if outgoing in symbols_by_memory_address:
|
||||
outgoing = symbols_by_memory_address[outgoing]
|
||||
#print(outgoing)
|
||||
if outgoing["debug_type"] in ["DW_TAG_GNU_call_site", "DW_TAG_lexical_block"]:
|
||||
continue
|
||||
if outgoing["name"] == "audioio_wavefile_type":
|
||||
print(outgoing)
|
||||
converted.add(outgoing["name"])
|
||||
symbol["outgoing_pointers"] = converted
|
||||
|
||||
print("linking back")
|
||||
# Link back
|
||||
for symbol_name in all_symbols:
|
||||
symbol = all_symbols[symbol_name]
|
||||
if "outgoing_jumps" in symbol:
|
||||
for outgoing in symbol["outgoing_jumps"]:
|
||||
if outgoing not in all_symbols:
|
||||
#print(outgoing, symbol_name)
|
||||
continue
|
||||
#print(all_symbols[outgoing], symbol_name)
|
||||
|
||||
referenced_symbol = all_symbols[outgoing]
|
||||
if "incoming_jumps" not in referenced_symbol:
|
||||
#print(symbol_name, "->", outgoing)
|
||||
referenced_symbol["incoming_jumps"] = set()
|
||||
referenced_symbol["incoming_jumps"].add(symbol_name)
|
||||
if "outgoing_pointers" in symbol:
|
||||
for outgoing in symbol["outgoing_pointers"]:
|
||||
if outgoing not in all_symbols:
|
||||
#print(outgoing, symbol_name)
|
||||
continue
|
||||
#print(all_symbols[outgoing], symbol_name)
|
||||
|
||||
referenced_symbol = all_symbols[outgoing]
|
||||
if "incoming_pointers" not in referenced_symbol:
|
||||
#print(symbol_name, "->", outgoing)
|
||||
referenced_symbol["incoming_pointers"] = set()
|
||||
referenced_symbol["incoming_pointers"].add(symbol_name)
|
||||
|
||||
print(all_symbols["exception_table"])
|
||||
|
||||
# Chart it all
|
||||
print("charting {} symbols".format(len(all_symbols)))
|
||||
callgraph = pgv.AGraph(directed=True)
|
||||
for i, symbol_name in enumerate(all_symbols):
|
||||
symbol = all_symbols[symbol_name]
|
||||
# print(i, symbol_name)
|
||||
# if "outgoing_jumps" in symbol:
|
||||
# print(" ", len(symbol["outgoing_jumps"]), "jumps")
|
||||
# if "outgoing_pointers" in symbol:
|
||||
# print(" ", len(symbol["outgoing_pointers"]), "ptrs")
|
||||
# if i > 3000:
|
||||
# break
|
||||
if ("incoming_jumps" not in symbol or len(symbol["incoming_jumps"]) == 0) and ("incoming_pointers" not in symbol or len(symbol["incoming_pointers"]) == 0):
|
||||
#print(symbol_name)
|
||||
continue
|
||||
if "start_address" not in symbol:
|
||||
continue
|
||||
callgraph.add_node(symbol_name)
|
||||
if "outgoing_jumps" in symbol:
|
||||
for outgoing in symbol["outgoing_jumps"]:
|
||||
callgraph.add_edge(symbol_name, outgoing)
|
||||
if "outgoing_pointers" in symbol:
|
||||
for outgoing in symbol["outgoing_pointers"]:
|
||||
callgraph.add_edge(symbol_name, outgoing, color="red")
|
||||
#print(symbol_name, symbol)
|
||||
|
||||
# Style all of the nodes
|
||||
print("styling")
|
||||
for node in callgraph.iternodes():
|
||||
if node.name not in all_symbols:
|
||||
continue
|
||||
symbol = all_symbols[node.name]
|
||||
node.attr["shape"] = "box"
|
||||
text_width_ish = len(node.name) * 0.1
|
||||
if "size" not in symbol:
|
||||
print(symbol)
|
||||
size = symbol["size"] / 8
|
||||
square_size = size ** 0.5
|
||||
if text_width_ish > square_size:
|
||||
w = text_width_ish
|
||||
h = size / text_width_ish
|
||||
else:
|
||||
w = square_size
|
||||
h = square_size
|
||||
node.attr["width"] = w
|
||||
node.attr["height"] = h
|
||||
node.attr["label"] = node.name + "\r\n" + str(symbol["size"]) + " bytes"
|
||||
node.attr["style"] = "filled"
|
||||
|
||||
incoming = 0
|
||||
if "incoming_jumps" in symbol:
|
||||
incoming += len(symbol["incoming_jumps"])
|
||||
if "incoming_pointers" in symbol:
|
||||
incoming += len(symbol["incoming_pointers"])
|
||||
|
||||
if node.name in SPECIAL_NODE_COLORS:
|
||||
node.attr["color"] = SPECIAL_NODE_COLORS[node.name]
|
||||
elif incoming == 1:
|
||||
node.attr["color"] = "lightblue"
|
||||
elif incoming > 25:
|
||||
print("delete", node.name, "because it has {} incoming".format(incoming))
|
||||
callgraph.delete_node(node.name)
|
||||
elif incoming > 15:
|
||||
node.attr["color"] = "red"
|
||||
|
||||
print("drawing")
|
||||
callgraph.layout(prog="dot")
|
||||
fn = "callgraph.svg"
|
||||
print(fn)
|
||||
callgraph.draw(fn)
|
||||
|
||||
if __name__ == "__main__":
|
||||
do_all_the_things()
|
Loading…
x
Reference in New Issue
Block a user