summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2018-06-08 17:59:06 -0400
committerGitHub <noreply@github.com>2018-06-08 17:59:06 -0400
commitb2d98edb4ed99efabd862e540613e4ac8550b50d (patch)
treec6f44d80d34f232777904ed14886c1578c19fcf9
parent4e4d795da54605b3a541861b4ed387119808f1b4 (diff)
parent8fb34a584664c800a4ea4d2d4c351c822bb03a98 (diff)
Merge pull request #901 from tannewt/pulseio_too_fast
Prevent freezing USB during high frequency PulseIn.
-rw-r--r--ports/atmel-samd/background.c8
-rw-r--r--ports/atmel-samd/background.h3
-rw-r--r--ports/atmel-samd/bindings/samd/Clock.c10
-rw-r--r--ports/atmel-samd/bindings/samd/Clock.h10
-rw-r--r--ports/atmel-samd/boards/arduino_zero/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/feather_m0_express/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/gemma_m0/mpconfigboard.h3
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/metro_m0_express/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/trinket_m0/mpconfigboard.h3
-rw-r--r--ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/boards/ugame10/mpconfigboard.h4
-rw-r--r--ports/atmel-samd/common-hal/microcontroller/__init__.c14
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseIn.c16
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseIn.h1
-rw-r--r--ports/atmel-samd/peripherals/samd21/clocks.c3
-rw-r--r--ports/atmel-samd/tick.c16
-rw-r--r--ports/nrf/common-hal/pulseio/PulseIn.c4
-rw-r--r--shared-bindings/pulseio/PulseIn.c23
-rw-r--r--shared-bindings/pulseio/PulseIn.h1
-rw-r--r--tools/chart_code_size.py454
31 files changed, 608 insertions, 25 deletions
diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c
index 92648f42e..4cba7a110 100644
--- a/ports/atmel-samd/background.c
+++ b/ports/atmel-samd/background.c
@@ -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;
}
diff --git a/ports/atmel-samd/background.h b/ports/atmel-samd/background.h
index f7fb10a1f..e841049a4 100644
--- a/ports/atmel-samd/background.h
+++ b/ports/atmel-samd/background.h
@@ -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
diff --git a/ports/atmel-samd/bindings/samd/Clock.c b/ports/atmel-samd/bindings/samd/Clock.c
index 3c87177a4..e09cc0bd8 100644
--- a/ports/atmel-samd/bindings/samd/Clock.c
+++ b/ports/atmel-samd/bindings/samd/Clock.c
@@ -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
diff --git a/ports/atmel-samd/bindings/samd/Clock.h b/ports/atmel-samd/bindings/samd/Clock.h
index 0d13ae253..ccc8f10d1 100644
--- a/ports/atmel-samd/bindings/samd/Clock.h
+++ b/ports/atmel-samd/bindings/samd/Clock.h
@@ -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, \
}
diff --git a/ports/atmel-samd/boards/arduino_zero/mpconfigboard.h b/ports/atmel-samd/boards/arduino_zero/mpconfigboard.h
index a32f128f5..1382d4736 100644
--- a/ports/atmel-samd/boards/arduino_zero/mpconfigboard.h
+++ b/ports/atmel-samd/boards/arduino_zero/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
index 3d97e2cb1..5077840cb 100644
--- a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
+++ b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h b/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h
index 83cc19d9f..638a6646c 100644
--- a/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h
+++ b/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h
index 94caa7d04..c8b5c56ee 100644
--- a/ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h
+++ b/ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.h
index 34de8e166..dcac9749d 100644
--- a/ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.h
+++ b/ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.h
index bfa8c642a..108d67d9f 100644
--- a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.h
+++ b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.h
index 4f4ea2ffe..4a530ed29 100644
--- a/ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.h
+++ b/ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.h
index a9d586c2e..3a6f28c12 100644
--- a/ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.h
+++ b/ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h
index c8118e48b..a7a2d7de0 100644
--- a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h
+++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h
index bb5c0ddcc..c82395baf 100644
--- a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h
+++ b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/gemma_m0/mpconfigboard.h b/ports/atmel-samd/boards/gemma_m0/mpconfigboard.h
index 53e802f17..1ec217096 100644
--- a/ports/atmel-samd/boards/gemma_m0/mpconfigboard.h
+++ b/ports/atmel-samd/boards/gemma_m0/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.h b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.h
index 3adcb7f16..f56f57c46 100644
--- a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.h
+++ b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.h b/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.h
index 116d4dac6..e47d5390d 100644
--- a/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.h
+++ b/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.h b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.h
index f798c5d36..135d6ae92 100644
--- a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.h
+++ b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h
index 4d206a4c8..050f678dd 100644
--- a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h
+++ b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/trinket_m0/mpconfigboard.h b/ports/atmel-samd/boards/trinket_m0/mpconfigboard.h
index d561947e3..9036f8e7b 100644
--- a/ports/atmel-samd/boards/trinket_m0/mpconfigboard.h
+++ b/ports/atmel-samd/boards/trinket_m0/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.h b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.h
index 3377d1b7e..8e3fdd7a8 100644
--- a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.h
+++ b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/boards/ugame10/mpconfigboard.h b/ports/atmel-samd/boards/ugame10/mpconfigboard.h
index 4e5e88569..ed822952d 100644
--- a/ports/atmel-samd/boards/ugame10/mpconfigboard.h
+++ b/ports/atmel-samd/boards/ugame10/mpconfigboard.h
@@ -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
diff --git a/ports/atmel-samd/common-hal/microcontroller/__init__.c b/ports/atmel-samd/common-hal/microcontroller/__init__.c
index c57b6939c..ad4d81ddd 100644
--- a/ports/atmel-samd/common-hal/microcontroller/__init__.c
+++ b/ports/atmel-samd/common-hal/microcontroller/__init__.c
@@ -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;
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
index 99a60a829..d16bbf9d2 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c
+++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
@@ -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(&current_ms, &current_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();
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.h b/ports/atmel-samd/common-hal/pulseio/PulseIn.h
index 3d79b50c3..f5326d9e5 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseIn.h
+++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.h
@@ -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);
diff --git a/ports/atmel-samd/peripherals/samd21/clocks.c b/ports/atmel-samd/peripherals/samd21/clocks.c
index 51b7ad993..422290e8b 100644
--- a/ports/atmel-samd/peripherals/samd21/clocks.c
+++ b/ports/atmel-samd/peripherals/samd21/clocks.c
@@ -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) {
diff --git a/ports/atmel-samd/tick.c b/ports/atmel-samd/tick.c
index 6cd7c7833..9753a1a0c 100644
--- a/ports/atmel-samd/tick.c
+++ b/ports/atmel-samd/tick.c
@@ -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) {
diff --git a/ports/nrf/common-hal/pulseio/PulseIn.c b/ports/nrf/common-hal/pulseio/PulseIn.c
index aa6bb8665..e759ac3a3 100644
--- a/ports/nrf/common-hal/pulseio/PulseIn.c
+++ b/ports/nrf/common-hal/pulseio/PulseIn.c
@@ -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;
}
diff --git a/shared-bindings/pulseio/PulseIn.c b/shared-bindings/pulseio/PulseIn.c
index 736441c74..862dbd99d 100644
--- a/shared-bindings/pulseio/PulseIn.c
+++ b/shared-bindings/pulseio/PulseIn.c
@@ -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);
diff --git a/shared-bindings/pulseio/PulseIn.h b/shared-bindings/pulseio/PulseIn.h
index 88b6f356e..e28a3c2df 100644
--- a/shared-bindings/pulseio/PulseIn.h
+++ b/shared-bindings/pulseio/PulseIn.h
@@ -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);
diff --git a/tools/chart_code_size.py b/tools/chart_code_size.py
new file mode 100644
index 000000000..0b55787fa
--- /dev/null
+++ b/tools/chart_code_size.py
@@ -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()