summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--py/builtin.c14
-rw-r--r--py/builtin.h2
-rw-r--r--py/builtintables.c2
-rw-r--r--py/makeqstrdata.py2
-rw-r--r--py/obj.c2
-rw-r--r--py/objstr.c7
-rw-r--r--py/objstr.h2
-rw-r--r--py/qstrdefs.h4
-rw-r--r--stmhal/Makefile19
-rw-r--r--stmhal/adc.c32
-rw-r--r--stmhal/dac.c42
-rw-r--r--stmhal/flash.c77
-rw-r--r--stmhal/flash.h1
-rw-r--r--stmhal/i2c.c69
-rw-r--r--stmhal/main.c33
-rw-r--r--stmhal/math.c81
-rw-r--r--stmhal/mathsincos.c601
-rw-r--r--stmhal/modpyb.c11
-rw-r--r--stmhal/pybcdc.h92
-rw-r--r--[-rwxr-xr-x]stmhal/pybcdc.inf_template (renamed from stmhal/pybcdc.inf)4
-rw-r--r--stmhal/pybstdio.c4
-rw-r--r--stmhal/pyexec.c1
-rw-r--r--stmhal/qstrdefsport.h3
-rw-r--r--stmhal/stm32f4xx_it.c14
-rw-r--r--stmhal/storage.c77
-rw-r--r--stmhal/storage.h2
-rw-r--r--stmhal/timer.c42
-rw-r--r--stmhal/timer.h2
-rw-r--r--stmhal/usbd_cdc_interface.c121
-rw-r--r--stmhal/usbd_msc_storage.c41
-rw-r--r--stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h7
-rw-r--r--stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c19
-rw-r--r--stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c33
-rw-r--r--tests/basics/builtin-bin.py12
-rw-r--r--tests/basics/builtin-hex.py12
-rw-r--r--tests/basics/builtin-oct.py12
-rw-r--r--tests/basics/fun-callstar.py2
-rw-r--r--tests/basics/fun-defargs.py2
-rw-r--r--tests/basics/memoryerror.py17
-rw-r--r--tests/bytecode/README.md2
-rwxr-xr-xtests/run-tests22
-rw-r--r--tools/file2h.py30
-rw-r--r--tools/insert-usb-ids.py36
-rw-r--r--unix/Makefile10
-rw-r--r--unix/mpconfigport.mk3
45 files changed, 1404 insertions, 219 deletions
diff --git a/py/builtin.c b/py/builtin.c
index 5911fa634..5e2015452 100644
--- a/py/builtin.c
+++ b/py/builtin.c
@@ -6,6 +6,7 @@
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
+#include "objstr.h"
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
@@ -125,6 +126,13 @@ STATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any);
+STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) {
+ mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in };
+ return mp_obj_str_format(sizeof(args) / sizeof(args[0]), args);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin);
+
STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
if (mp_obj_is_callable(o_in)) {
return mp_const_true;
@@ -299,6 +307,12 @@ STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next);
+STATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) {
+ return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_o), o_in);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct);
+
STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
uint len;
const char *str = mp_obj_str_get_data(o_in, &len);
diff --git a/py/builtin.h b/py/builtin.h
index 51a74a310..36b9f3881 100644
--- a/py/builtin.h
+++ b/py/builtin.h
@@ -6,6 +6,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin___repl_print___obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_abs_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bin_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj);
@@ -26,6 +27,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_locals_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_max_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_min_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_next_obj);
+MP_DECLARE_CONST_FUN_OBJ(mp_builtin_oct_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_ord_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_pow_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_print_obj);
diff --git a/py/builtintables.c b/py/builtintables.c
index 6cf12dffa..6bdae2400 100644
--- a/py/builtintables.c
+++ b/py/builtintables.c
@@ -51,6 +51,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_abs), (mp_obj_t)&mp_builtin_abs_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_all), (mp_obj_t)&mp_builtin_all_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&mp_builtin_any_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_bin), (mp_obj_t)&mp_builtin_bin_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_callable), (mp_obj_t)&mp_builtin_callable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_chr), (mp_obj_t)&mp_builtin_chr_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_dir), (mp_obj_t)&mp_builtin_dir_obj },
@@ -70,6 +71,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_max), (mp_obj_t)&mp_builtin_max_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_min), (mp_obj_t)&mp_builtin_min_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_next), (mp_obj_t)&mp_builtin_next_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_oct), (mp_obj_t)&mp_builtin_oct_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ord), (mp_obj_t)&mp_builtin_ord_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_pow), (mp_obj_t)&mp_builtin_pow_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_print), (mp_obj_t)&mp_builtin_print_obj },
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index 8620af567..afde77205 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -18,6 +18,8 @@ codepoint2name[ord(':')] = 'colon'
codepoint2name[ord('/')] = 'slash'
codepoint2name[ord('%')] = 'percent'
codepoint2name[ord('#')] = 'hash'
+codepoint2name[ord('{')] = 'brace_open'
+codepoint2name[ord('}')] = 'brace_close'
# this must match the equivalent function in qstr.c
def compute_hash(qstr):
diff --git a/py/obj.c b/py/obj.c
index 078284f2a..76350ed6d 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -320,7 +320,7 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index,
// may return MP_OBJ_NULL
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
- if (MP_OBJ_IS_STR(o_in)) {
+ if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
return MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_str_get_len(o_in));
} else {
mp_obj_type_t *type = mp_obj_get_type(o_in);
diff --git a/py/objstr.c b/py/objstr.c
index fc1e1c569..7de42b6e9 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -579,7 +579,7 @@ static mp_obj_t arg_as_int(mp_obj_t arg) {
return arg;
}
-mp_obj_t str_format(uint n_args, const mp_obj_t *args) {
+mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
assert(MP_OBJ_IS_STR(args[0]));
GET_STR_DATA_LEN(args[0], str, len);
@@ -1346,7 +1346,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_startswith_obj, str_startswith);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, str_format);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, mp_obj_str_format);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
@@ -1485,7 +1485,8 @@ uint mp_obj_str_get_hash(mp_obj_t self_in) {
}
uint mp_obj_str_get_len(mp_obj_t self_in) {
- if (MP_OBJ_IS_STR(self_in)) {
+ // TODO This has a double check for the type, one in obj.c and one here
+ if (MP_OBJ_IS_STR(self_in) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytes)) {
GET_STR_LEN(self_in, l);
return l;
} else {
diff --git a/py/objstr.h b/py/objstr.h
index a32ba53b1..800568de8 100644
--- a/py/objstr.h
+++ b/py/objstr.h
@@ -8,3 +8,5 @@ typedef struct _mp_obj_str_t {
} mp_obj_str_t;
#define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str};
+
+mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args);
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index d18882f69..20c4db75f 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -83,6 +83,8 @@ Q(all)
Q(any)
Q(args)
Q(array)
+Q(bin)
+Q({:#b})
Q(bool)
Q(bytearray)
Q(bytes)
@@ -122,6 +124,8 @@ Q(max)
Q(min)
Q(namedtuple)
Q(next)
+Q(oct)
+Q(%#o)
Q(open)
Q(ord)
Q(path)
diff --git a/stmhal/Makefile b/stmhal/Makefile
index 978918994..56c00e905 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -70,6 +70,7 @@ SRC_C = \
usb.c \
printf.c \
math.c \
+ mathsincos.c \
malloc0.c \
gccollect.c \
pybstdio.c \
@@ -210,6 +211,14 @@ PREFIX_FILE = boards/stm32f4xx-prefix.c
GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
GEN_PINS_HDR = $(BUILD)/pins.h
+INSERT_USB_IDS = ../tools/insert-usb-ids.py
+FILE2H = ../tools/file2h.py
+
+USB_IDS_FILE = usbd_desc_cdc_msc.c
+CDCINF_TEMPLATE = pybcdc.inf_template
+GEN_CDCINF_FILE = $(BUILD)/pybcdc.inf
+GEN_CDCINF_HEADER = $(BUILD)/pybcdc_inf.h
+
# Making OBJ use an order-only depenedency on the generated pins.h file
# has the side effect of making the pins.h file before we actually compile
# any of the objects. The normal dependency generation will deal with the
@@ -217,6 +226,8 @@ GEN_PINS_HDR = $(BUILD)/pins.h
# which source files might need it.
$(OBJ): | $(BUILD)/pins.h
+$(BUILD)/main.o: $(GEN_CDCINF_HEADER)
+
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_$(BOARD).c and pins.h
$(BUILD)/%_$(BOARD).c $(BUILD)/%.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE)
@@ -226,4 +237,12 @@ $(BUILD)/%_$(BOARD).c $(BUILD)/%.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE
$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
$(call compile_c)
+$(GEN_CDCINF_HEADER): $(GEN_CDCINF_FILE) $(FILE2H)
+ $(ECHO) "Create $@"
+ $(Q)$(PYTHON) $(FILE2H) $< > $@
+
+$(GEN_CDCINF_FILE): $(CDCINF_TEMPLATE) $(INSERT_USB_IDS) $(USB_IDS_FILE)
+ $(ECHO) "Create $@"
+ $(Q)$(PYTHON) $(INSERT_USB_IDS) $(USB_IDS_FILE) $< > $@
+
include ../py/mkrules.mk
diff --git a/stmhal/adc.c b/stmhal/adc.c
index 8a1c23c4f..dafa3f7bc 100644
--- a/stmhal/adc.c
+++ b/stmhal/adc.c
@@ -11,6 +11,7 @@
#include "adc.h"
#include "pin.h"
#include "build/pins.h"
+#include "timer.h"
// Usage Model:
//
@@ -162,8 +163,39 @@ STATIC mp_obj_t adc_read(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
+STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) {
+ pyb_obj_adc_t *self = self_in;
+
+ buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo);
+
+ // Init TIM6 at the required frequency (in Hz)
+ timer_tim6_init(mp_obj_get_int(freq_in));
+
+ // Start timer
+ HAL_TIM_Base_Start(&TIM6_Handle);
+
+ // This uses the timer in polling mode to do the sampling
+ // TODO use DMA
+ for (uint i = 0; i < bufinfo.len; i++) {
+ // Wait for the timer to trigger
+ while (__HAL_TIM_GET_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE) == RESET) {
+ }
+ __HAL_TIM_CLEAR_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE);
+ ((byte*)bufinfo.buf)[i] = adc_read_channel(&self->handle) >> 4;
+ }
+
+ // Stop timer
+ HAL_TIM_Base_Stop(&TIM6_Handle);
+
+ return mp_obj_new_int(bufinfo.len);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed);
+
STATIC const mp_map_elem_t adc_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read_timed), (mp_obj_t)&adc_read_timed_obj},
};
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
diff --git a/stmhal/dac.c b/stmhal/dac.c
index 5e809412e..c018a4046 100644
--- a/stmhal/dac.c
+++ b/stmhal/dac.c
@@ -10,9 +10,9 @@
#include "parse.h"
#include "obj.h"
#include "runtime.h"
+#include "timer.h"
#include "dac.h"
-TIM_HandleTypeDef TIM6_Handle;
STATIC DAC_HandleTypeDef DAC_Handle;
void dac_init(void) {
@@ -22,19 +22,8 @@ void dac_init(void) {
}
STATIC void TIM6_Config(uint freq) {
- // TIM6 clock enable
- __TIM6_CLK_ENABLE();
-
- // Compute the prescaler value so TIM6 triggers at freq-Hz
- uint16_t period = (uint16_t) ((SystemCoreClock / 2) / freq) - 1;
-
- // time base clock configuration
- TIM6_Handle.Instance = TIM6;
- TIM6_Handle.Init.Period = period;
- TIM6_Handle.Init.Prescaler = 0; // timer runs at SystemCoreClock / 2
- TIM6_Handle.Init.ClockDivision = 0; // unused for TIM6
- TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
- HAL_TIM_Base_Init(&TIM6_Handle);
+ // Init TIM6 at the required frequency (in Hz)
+ timer_tim6_init(freq);
// TIM6 TRGO selection
TIM_MasterConfigTypeDef config;
@@ -203,17 +192,14 @@ mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
DAC_Init(self->dac_channel, &DAC_InitStructure);
*/
- if (self->state != 3) {
- DAC_ChannelConfTypeDef config;
- config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
- config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
- HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
- self->state = 3;
- }
-
// DMA1_Stream[67] channel7 configuration
DMA_HandleTypeDef DMA_Handle;
DMA_Handle.Instance = self->dma_stream;
+
+ // Need to deinit DMA first
+ DMA_Handle.State = HAL_DMA_STATE_READY;
+ HAL_DMA_DeInit(&DMA_Handle);
+
DMA_Handle.Init.Channel = DMA_CHANNEL_7;
DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
@@ -231,6 +217,18 @@ mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
__HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle);
+ DAC_Handle.Instance = DAC;
+ DAC_Handle.State = HAL_DAC_STATE_RESET;
+ HAL_DAC_Init(&DAC_Handle);
+
+ if (self->state != 3) {
+ DAC_ChannelConfTypeDef config;
+ config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
+ config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
+ HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
+ self->state = 3;
+ }
+
HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R);
/*
diff --git a/stmhal/flash.c b/stmhal/flash.c
index 6ed3b0432..ce16fe271 100644
--- a/stmhal/flash.c
+++ b/stmhal/flash.c
@@ -49,7 +49,81 @@ uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *si
return 0;
}
+void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+ // check there is something to write
+ if (num_word32 == 0) {
+ return;
+ }
+
+ // unlock
+ HAL_FLASH_Unlock();
+
+ // Clear pending flags (if any)
+ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
+ FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
+
+ // erase the sector(s)
+ FLASH_EraseInitTypeDef EraseInitStruct;
+ EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
+ EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
+ EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL);
+ EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1;
+ uint32_t SectorError = 0;
+ if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
+ // error occurred during sector erase
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+}
+
+/*
+// erase the sector using an interrupt
+void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+ // check there is something to write
+ if (num_word32 == 0) {
+ return;
+ }
+
+ // unlock
+ HAL_FLASH_Unlock();
+
+ // Clear pending flags (if any)
+ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
+ FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
+
+ // erase the sector(s)
+ FLASH_EraseInitTypeDef EraseInitStruct;
+ EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
+ EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
+ EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL);
+ EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1;
+ if (HAL_FLASHEx_Erase_IT(&EraseInitStruct) != HAL_OK) {
+ // error occurred during sector erase
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+}
+*/
+
void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
+ // program the flash word by word
+ for (int i = 0; i < num_word32; i++) {
+ if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) {
+ // error occurred during flash write
+ HAL_FLASH_Lock(); // lock the flash
+ return;
+ }
+ flash_dest += 4;
+ src += 1;
+ }
+
+ // lock the flash
+ HAL_FLASH_Lock();
+}
+
+/*
+ use erase, then write
+void flash_erase_and_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
// check there is something to write
if (num_word32 == 0) {
return;
@@ -71,6 +145,7 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32)
uint32_t SectorError = 0;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
// error occurred during sector erase
+ HAL_FLASH_Lock(); // lock the flash
return;
}
@@ -78,6 +153,7 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32)
for (int i = 0; i < num_word32; i++) {
if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) {
// error occurred during flash write
+ HAL_FLASH_Lock(); // lock the flash
return;
}
flash_dest += 4;
@@ -87,3 +163,4 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32)
// lock the flash
HAL_FLASH_Lock();
}
+*/
diff --git a/stmhal/flash.h b/stmhal/flash.h
index 33d31df7a..7900d2c1a 100644
--- a/stmhal/flash.h
+++ b/stmhal/flash.h
@@ -1,2 +1,3 @@
uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size);
+void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32);
void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32);
diff --git a/stmhal/i2c.c b/stmhal/i2c.c
index 65bc3600e..780d4fb49 100644
--- a/stmhal/i2c.c
+++ b/stmhal/i2c.c
@@ -98,14 +98,13 @@ STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
return (mp_obj_t)i2c_obj;
}
+// Check if an I2C device responds to the given address.
STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
pyb_i2c_obj_t *self = self_in;
machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1;
- //printf("IsDeviceReady\n");
for (int i = 0; i < 10; i++) {
HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c_handle, i2c_addr, 10, 200);
- //printf(" got %d\n", status);
if (status == HAL_OK) {
return mp_const_true;
}
@@ -116,6 +115,69 @@ STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) {
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready);
+// Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
+STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
+ pyb_i2c_obj_t *self = self_in;
+
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+
+ for (uint addr = 1; addr <= 127; addr++) {
+ for (int i = 0; i < 10; i++) {
+ HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c_handle, addr << 1, 10, 200);
+ if (status == HAL_OK) {
+ mp_obj_list_append(list, mp_obj_new_int(addr));
+ break;
+ }
+ }
+ }
+
+ return list;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan);
+
+STATIC mp_obj_t pyb_i2c_read(mp_obj_t self_in, mp_obj_t i2c_addr_in, mp_obj_t n_in) {
+ pyb_i2c_obj_t *self = self_in;
+ machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_in) << 1;
+ machine_uint_t n = mp_obj_get_int(n_in);
+
+ byte *data;
+ mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, n, &data);
+ HAL_StatusTypeDef status = HAL_I2C_Master_Receive(self->i2c_handle, i2c_addr, data, n, 500);
+
+ if (status != HAL_OK) {
+ // TODO really need a HardwareError object, or something
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Master_Receive failed with code %d", status));
+ }
+
+ return mp_obj_str_builder_end(o);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_i2c_read_obj, pyb_i2c_read);
+
+STATIC mp_obj_t pyb_i2c_write(mp_obj_t self_in, mp_obj_t i2c_addr_in, mp_obj_t data_in) {
+ pyb_i2c_obj_t *self = self_in;
+ machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_in) << 1;
+ HAL_StatusTypeDef status;
+ if (MP_OBJ_IS_INT(data_in)) {
+ uint8_t data[1] = {mp_obj_get_int(data_in)};
+ status = HAL_I2C_Master_Transmit(self->i2c_handle, i2c_addr, data, 1, 500);
+ } else {
+ buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_in, &bufinfo);
+ status = HAL_I2C_Master_Transmit(self->i2c_handle, i2c_addr, bufinfo.buf, bufinfo.len, 500);
+ }
+
+ if (status != HAL_OK) {
+ // TODO really need a HardwareError object, or something
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Master_Transmit failed with code %d", status));
+ }
+
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_i2c_write_obj, pyb_i2c_write);
+
STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args) {
pyb_i2c_obj_t *self = args[0];
machine_uint_t i2c_addr = mp_obj_get_int(args[1]) << 1;
@@ -166,6 +228,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_i2c_mem_write_obj, 4, 4, pyb_i2c_
STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_is_ready), (mp_obj_t)&pyb_i2c_is_ready_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&pyb_i2c_scan_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&pyb_i2c_read_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_i2c_write_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_read), (mp_obj_t)&pyb_i2c_mem_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_write), (mp_obj_t)&pyb_i2c_mem_write_obj },
};
diff --git a/stmhal/main.c b/stmhal/main.c
index 2f40f140a..c5633fb68 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -134,7 +134,22 @@ static const char fresh_main_py[] =
;
static const char fresh_pybcdc_inf[] =
-#include "pybcdc.h"
+#include "build/pybcdc_inf.h"
+;
+
+static const char fresh_readme_txt[] =
+"This is a Micro Python board\r\n"
+"\r\n"
+"You can get started right away by writing your Python code in 'main.py'.\r\n"
+"\r\n"
+"For a serial prompt:\r\n"
+" - Windows: you need to go to 'Device manager', right click on the unknown device,\r\n"
+" then update the driver software, using the 'pybcdc.inf' file found on this drive.\r\n"
+" Then use a terminal program like Hyperterminal or putty.\r\n"
+" - Mac OS X: use the command: screen /dev/tty.usbmodem*\r\n"
+" - Linux: use the command: screen /dev/ttyACM0\r\n"
+"\r\n"
+"Please visit http://micropython.org/help/ for further help.\r\n"
;
int main(void) {
@@ -254,8 +269,15 @@ soft_reset:
// Change #if 0 to #if 1 if you want REPL on USART_6 (or another usart)
// as well as on USB VCP
#if 0
- pyb_usart_global_debug = pyb_Usart(MP_OBJ_NEW_SMALL_INT(PYB_USART_YA),
- MP_OBJ_NEW_SMALL_INT(115200));
+ {
+ mp_obj_t args[2] = {
+ MP_OBJ_NEW_SMALL_INT(PYB_USART_6),
+ MP_OBJ_NEW_SMALL_INT(115200),
+ };
+ pyb_usart_global_debug = pyb_usart_type.make_new((mp_obj_t)&pyb_usart_type,
+ sizeof(args) / sizeof(args[0]),
+ 0, args);
+ }
#else
pyb_usart_global_debug = NULL;
#endif
@@ -315,6 +337,11 @@ soft_reset:
f_write(&fp, fresh_pybcdc_inf, sizeof(fresh_pybcdc_inf) - 1 /* don't count null terminator */, &n);
f_close(&fp);
+ // create readme file
+ f_open(&fp, "0:/README.txt", FA_WRITE | FA_CREATE_ALWAYS);
+ f_write(&fp, fresh_readme_txt, sizeof(fresh_readme_txt) - 1 /* don't count null terminator */, &n);
+ f_close(&fp);
+
// keep LED on for at least 200ms
sys_tick_wait_at_least(start_tick, 200);
led_state(PYB_LED_R2, 0);
diff --git a/stmhal/math.c b/stmhal/math.c
index 9b815f118..75a5aeb2e 100644
--- a/stmhal/math.c
+++ b/stmhal/math.c
@@ -70,16 +70,11 @@ float tanhf(float x) { return sinhf(x) / coshf(x); }
float acoshf(float x) { return 0.0; }
float asinhf(float x) { return 0.0; }
float atanhf(float x) { return 0.0; }
-float cosf(float x) { return 0.0; }
-float sinf(float x) { return 0.0; }
float tanf(float x) { return 0.0; }
float acosf(float x) { return 0.0; }
float asinf(float x) { return 0.0; }
float atanf(float x) { return 0.0; }
float atan2f(float x, float y) { return 0.0; }
-float ceilf(float x) { return 0.0; }
-float floorf(float x) { return 0.0; }
-float truncf(float x) { return 0.0; }
float fmodf(float x, float y) { return 0.0; }
float tgammaf(float x) { return 0.0; }
float lgammaf(float x) { return 0.0; }
@@ -820,3 +815,79 @@ float sinhf(float x)
t = 2*h*__expo2f(absx);
return t;
}
+
+/*****************************************************************************/
+/*****************************************************************************/
+// ceilf, floorf and truncf from musl-0.9.15
+/*****************************************************************************/
+/*****************************************************************************/
+
+float ceilf(float x)
+{
+ union {float f; uint32_t i;} u = {x};
+ int e = (int)(u.i >> 23 & 0xff) - 0x7f;
+ uint32_t m;
+
+ if (e >= 23)
+ return x;
+ if (e >= 0) {
+ m = 0x007fffff >> e;
+ if ((u.i & m) == 0)
+ return x;
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31 == 0)
+ u.i += m;
+ u.i &= ~m;
+ } else {
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31)
+ u.f = -0.0;
+ else if (u.i << 1)
+ u.f = 1.0;
+ }
+ return u.f;
+}
+
+float floorf(float x)
+{
+ union {float f; uint32_t i;} u = {x};
+ int e = (int)(u.i >> 23 & 0xff) - 0x7f;
+ uint32_t m;
+
+ if (e >= 23)
+ return x;
+ if (e >= 0) {
+ m = 0x007fffff >> e;
+ if ((u.i & m) == 0)
+ return x;
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31)
+ u.i += m;
+ u.i &= ~m;
+ } else {
+ FORCE_EVAL(x + 0x1p120f);
+ if (u.i >> 31 == 0)
+ u.i = 0;
+ else if (u.i << 1)
+ u.f = -1.0;
+ }
+ return u.f;
+}
+
+float truncf(float x)
+{
+ union {float f; uint32_t i;} u = {x};
+ int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9;
+ uint32_t m;
+
+ if (e >= 23 + 9)
+ return x;
+ if (e < 9)
+ e = 1;
+ m = -1U >> e;
+ if ((u.i & m) == 0)
+ return x;
+ FORCE_EVAL(x + 0x1p120f);
+ u.i &= ~m;
+ return u.f;
+}
diff --git a/stmhal/mathsincos.c b/stmhal/mathsincos.c
new file mode 100644
index 000000000..420c8bba1
--- /dev/null
+++ b/stmhal/mathsincos.c
@@ -0,0 +1,601 @@
+// These math functions are taken from newlib 2.1.0, the newlib/libm directory.
+
+#include <stdint.h>
+#include <math.h>
+
+
+/* @(#)fdlibm.h 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#define FLT_UWORD_IS_FINITE(x) ((x)<0x7f800000L)
+
+/* A union which permits us to convert between a float and a 32 bit
+ int. */
+
+typedef union
+{
+ float value;
+ __uint32_t word;
+} ieee_float_shape_type;
+
+
+/* Get a 32 bit int from a float. */
+
+#define GET_FLOAT_WORD(i,d) \
+do { \
+ ieee_float_shape_type gf_u; \
+ gf_u.value = (d); \
+ (i) = gf_u.word; \
+} while (0)
+
+/* Set a float from a 32 bit int. */
+
+#define SET_FLOAT_WORD(d,i) \
+do { \
+ ieee_float_shape_type sf_u; \
+ sf_u.word = (i); \
+ (d) = sf_u.value; \
+} while (0)
+
+
+
+/* kf_rem_pio2.c -- float version of k_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* In the float version, the input parameter x contains 8 bit
+ integers, not 24 bit integers. 113 bit precision is not supported. */
+
+#ifdef __STDC__
+static const int init_jk[] = {4,7,9}; /* initial value for jk */
+#else
+static int init_jk[] = {4,7,9};
+#endif
+
+#ifdef __STDC__
+static const float PIo2[] = {
+#else
+static float PIo2[] = {
+#endif
+ 1.5703125000e+00, /* 0x3fc90000 */
+ 4.5776367188e-04, /* 0x39f00000 */
+ 2.5987625122e-05, /* 0x37da0000 */
+ 7.5437128544e-08, /* 0x33a20000 */
+ 6.0026650317e-11, /* 0x2e840000 */
+ 7.3896444519e-13, /* 0x2b500000 */
+ 5.3845816694e-15, /* 0x27c20000 */
+ 5.6378512969e-18, /* 0x22d00000 */
+ 8.3009228831e-20, /* 0x1fc40000 */
+ 3.2756352257e-22, /* 0x1bc60000 */
+ 6.3331015649e-25, /* 0x17440000 */
+};
+
+static const float
+zero = 0.0000000000e+00, /* 0x00000000 */
+one = 1.0000000000e+00, /* 0x3f800000 */
+two8 = 2.5600000000e+02, /* 0x43800000 */
+twon8 = 3.9062500000e-03; /* 0x3b800000 */
+
+int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __int32_t *ipio2)
+{
+ __int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+ float z,fw,f[20],fq[20],q[20];
+
+ /* initialize jk*/
+ jk = init_jk[prec];
+ jp = jk;
+
+ /* determine jx,jv,q0, note that 3>q0 */
+ jx = nx-1;
+ jv = (e0-3)/8; if(jv<0) jv=0;
+ q0 = e0-8*(jv+1);
+
+ /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+ j = jv-jx; m = jx+jk;
+ for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
+
+ /* compute q[0],q[1],...q[jk] */
+ for (i=0;i<=jk;i++) {
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+ }
+
+ jz = jk;
+recompute:
+ /* distill q[] into iq[] reversingly */
+ for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+ fw = (float)((__int32_t)(twon8* z));
+ iq[i] = (__int32_t)(z-two8*fw);
+ z = q[j-1]+fw;
+ }
+
+ /* compute n */
+ z = scalbnf(z,(int)q0); /* actual value of z */
+ z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
+ n = (__int32_t) z;
+ z -= (float)n;
+ ih = 0;
+ if(q0>0) { /* need iq[jz-1] to determine n */
+ i = (iq[jz-1]>>(8-q0)); n += i;
+ iq[jz-1] -= i<<(8-q0);
+ ih = iq[jz-1]>>(7-q0);
+ }
+ else if(q0==0) ih = iq[jz-1]>>8;
+ else if(z>=(float)0.5) ih=2;
+
+ if(ih>0) { /* q > 0.5 */
+ n += 1; carry = 0;
+ for(i=0;i<jz ;i++) { /* compute 1-q */
+ j = iq[i];
+ if(carry==0) {
+ if(j!=0) {
+ carry = 1; iq[i] = 0x100- j;
+ }
+ } else iq[i] = 0xff - j;
+ }
+ if(q0>0) { /* rare case: chance is 1 in 12 */
+ switch(q0) {
+ case 1:
+ iq[jz-1] &= 0x7f; break;
+ case 2:
+ iq[jz-1] &= 0x3f; break;
+ }
+ }
+ if(ih==2) {
+ z = one - z;
+ if(carry!=0) z -= scalbnf(one,(int)q0);
+ }
+ }
+
+ /* check if recomputation is needed */
+ if(z==zero) {
+ j = 0;
+ for (i=jz-1;i>=jk;i--) j |= iq[i];
+ if(j==0) { /* need recomputation */
+ for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
+
+ for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
+ f[jx+i] = (float) ipio2[jv+i];
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+ q[i] = fw;
+ }
+ jz += k;
+ goto recompute;
+ }
+ }
+
+ /* chop off zero terms */
+ if(z==(float)0.0) {
+ jz -= 1; q0 -= 8;
+ while(iq[jz]==0) { jz--; q0-=8;}
+ } else { /* break z into 8-bit if necessary */
+ z = scalbnf(z,-(int)q0);
+ if(z>=two8) {
+ fw = (float)((__int32_t)(twon8*z));
+ iq[jz] = (__int32_t)(z-two8*fw);
+ jz += 1; q0 += 8;
+ iq[jz] = (__int32_t) fw;
+ } else iq[jz] = (__int32_t) z ;
+ }
+
+ /* convert integer "bit" chunk to floating-point value */
+ fw = scalbnf(one,(int)q0);
+ for(i=jz;i>=0;i--) {
+ q[i] = fw*(float)iq[i]; fw*=twon8;
+ }
+
+ /* compute PIo2[0,...,jp]*q[jz,...,0] */
+ for(i=jz;i>=0;i--) {
+ for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+ fq[jz-i] = fw;
+ }
+
+ /* compress fq[] into y[] */
+ switch(prec) {
+ case 0:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ break;
+ case 1:
+ case 2:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ fw = fq[0]-fw;
+ for (i=1;i<=jz;i++) fw += fq[i];
+ y[1] = (ih==0)? fw: -fw;
+ break;
+ case 3: /* painful */
+ for (i=jz;i>0;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (i=jz;i>1;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+ if(ih==0) {
+ y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
+ } else {
+ y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+ }
+ }
+ return n&7;
+}
+
+
+/* ef_rem_pio2.c -- float version of e_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2f(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2f()
+ */
+
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+static const __int32_t two_over_pi[] = {
+0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC,
+0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62,
+0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63,
+0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A,
+0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09,
+0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29,
+0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44,
+0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41,
+0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C,
+0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8,
+0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11,
+0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF,
+0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E,
+0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5,
+0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92,
+0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08,
+0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0,
+0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3,
+0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85,
+0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80,
+0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA,
+0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B,
+};
+
+/* This array is like the one in e_rem_pio2.c, but the numbers are
+ single precision and the last 8 bits are forced to 0. */
+static const __int32_t npio2_hw[] = {
+0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00,
+0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00,
+0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100,
+0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00,
+0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00,
+0x4242c700, 0x42490f00
+};
+
+/*
+ * invpio2: 24 bits of 2/pi
+ * pio2_1: first 17 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ * pio2_2: second 17 bit of pi/2
+ * pio2_2t: pi/2 - (pio2_1+pio2_2)
+ * pio2_3: third 17 bit of pi/2
+ * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const float
+half = 5.0000000000e-01, /* 0x3f000000 */
+invpio2 = 6.3661980629e-01, /* 0x3f22f984 */
+pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */
+pio2_1t = 1.0804334124e-05, /* 0x37354443 */
+pio2_2 = 1.0804273188e-05, /* 0x37354400 */
+pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */
+pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */
+pio2_3t = 6.1232342629e-17; /* 0x248d3132 */
+
+__int32_t __ieee754_rem_pio2f(float x, float *y)
+{
+ float z,w,t,r,fn;
+ float tx[3];
+ __int32_t i,j,n,ix,hx;
+ int e0,nx;
+
+ GET_FLOAT_WORD(hx,x);
+ ix = hx&0x7fffffff;
+ if(ix<=0x3f490fd8) /* |x| ~<= pi/4 , no need for reduction */
+ {y[0] = x; y[1] = 0; return 0;}
+ if(ix<0x4016cbe4) { /* |x| < 3pi/4, special case with n=+-1 */
+ if(hx>0) {
+ z = x - pio2_1;
+ if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+ y[0] = z - pio2_1t;
+ y[1] = (z-y[0])-pio2_1t;
+ } else { /* near pi/2, use 24+24+24 bit pi */
+ z -= pio2_2;
+ y[0] = z - pio2_2t;
+ y[1] = (z-y[0])-pio2_2t;
+ }
+ return 1;
+ } else { /* negative x */
+ z = x + pio2_1;
+ if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+ y[0] = z + pio2_1t;
+ y[1] = (z-y[0])+pio2_1t;
+ } else { /* near pi/2, use 24+24+24 bit pi */
+ z += pio2_2;
+ y[0] = z + pio2_2t;
+ y[1] = (z-y[0])+pio2_2t;
+ }
+ return -1;
+ }
+ }
+ if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */
+ t = fabsf(x);
+ n = (__int32_t) (t*invpio2+half);
+ fn = (float)n;
+ r = t-fn*pio2_1;
+ w = fn*pio2_1t; /* 1st round good to 40 bit */
+ if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) {
+ y[0] = r-w; /* quick check no cancellation */
+ } else {
+ __uint32_t high;
+ j = ix>>23;
+ y[0] = r-w;
+ GET_FLOAT_WORD(high,y[0]);
+ i = j-((high>>23)&0xff);
+ if(i>8) { /* 2nd iteration needed, good to 57 */
+ t = r;
+ w = fn*pio2_2;
+ r = t-w;
+ w = fn*pio2_2t-((t-r)-w);
+ y[0] = r-w;
+ GET_FLOAT_WORD(high,y[0]);
+ i = j-((high>>23)&0xff);
+ if(i>25) { /* 3rd iteration need, 74 bits acc */
+ t = r; /* will cover all possible cases */
+ w = fn*pio2_3;
+ r = t-w;
+ w = fn*pio2_3t-((t-r)-w);
+ y[0] = r-w;
+ }
+ }
+ }
+ y[1] = (r-y[0])-w;
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ else return n;
+ }
+ /*
+ * all other (large) arguments
+ */
+ if(!FLT_UWORD_IS_FINITE(ix)) {
+ y[0]=y[1]=x-x; return 0;
+ }
+ /* set z = scalbn(|x|,ilogb(x)-7) */
+ e0 = (int)((ix>>23)-134); /* e0 = ilogb(z)-7; */
+ SET_FLOAT_WORD(z, ix - ((__int32_t)e0<<23));
+ for(i=0;i<2;i++) {
+ tx[i] = (float)((__int32_t)(z));
+ z = (z-tx[i])*two8;
+ }
+ tx[2] = z;
+ nx = 3;
+ while(tx[nx-1]==zero) nx--; /* skip zero term */
+ n = __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi);
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ return n;
+}
+
+
+/* kf_sin.c -- float version of k_sin.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+
+static const float
+S1 = -1.6666667163e-01, /* 0xbe2aaaab */
+S2 = 8.3333337680e-03, /* 0x3c088889 */
+S3 = -1.9841270114e-04, /* 0xb9500d01 */
+S4 = 2.7557314297e-06, /* 0x3638ef1b */
+S5 = -2.5050759689e-08, /* 0xb2d72f34 */
+S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */
+
+float __kernel_sinf(float x, float y, int iy) /* iy=0 if y is zero */
+{
+ float z,r,v;
+ __int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff; /* high word of x */
+ if(ix<0x32000000) /* |x| < 2**-27 */
+ {if((int)x==0) return x;} /* generate inexact */
+ z = x*x;
+ v = z*x;
+ r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
+ if(iy==0) return x+v*(S1+z*r);
+ else return x-((z*(half*y-v*r)-y)-v*S1);
+}
+
+
+
+/* kf_cos.c -- float version of k_cos.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+
+static const float
+C1 = 4.1666667908e-02, /* 0x3d2aaaab */
+C2 = -1.3888889225e-03, /* 0xbab60b61 */
+C3 = 2.4801587642e-05, /* 0x37d00d01 */
+C4 = -2.7557314297e-07, /* 0xb493f27c */
+C5 = 2.0875723372e-09, /* 0x310f74f6 */
+C6 = -1.1359647598e-11; /* 0xad47d74e */
+
+float __kernel_cosf(float x, float y)
+{
+ float a,hz,z,r,qx;
+ __int32_t ix;
+ GET_FLOAT_WORD(ix,x);
+ ix &= 0x7fffffff; /* ix = |x|'s high word*/
+ if(ix<0x32000000) { /* if x < 2**27 */
+ if(((int)x)==0) return one; /* generate inexact */
+ }
+ z = x*x;
+ r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+ if(ix < 0x3e99999a) /* if |x| < 0.3 */
+ return one - ((float)0.5*z - (z*r - x*y));
+ else {
+ if(ix > 0x3f480000) { /* x > 0.78125 */
+ qx = (float)0.28125;
+ } else {
+ SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */
+ }
+ hz = (float)0.5*z-qx;
+ a = one-qx;
+ return a - (hz - (z*r-x*y));
+ }
+}
+
+
+/* sf_sin.c -- float version of s_sin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+
+float sinf(float x)
+{
+ float y[2],z=0.0;
+ __int32_t n,ix;
+
+ GET_FLOAT_WORD(ix,x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0);
+
+ /* sin(Inf or NaN) is NaN */
+ else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2f(x,y);
+ switch(n&3) {
+ case 0: return __kernel_sinf(y[0],y[1],1);
+ case 1: return __kernel_cosf(y[0],y[1]);
+ case 2: return -__kernel_sinf(y[0],y[1],1);
+ default:
+ return -__kernel_cosf(y[0],y[1]);
+ }
+ }
+}
+
+
+/* sf_cos.c -- float version of s_cos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+
+float cosf(float x)
+{
+ float y[2],z=0.0;
+ __int32_t n,ix;
+
+ GET_FLOAT_WORD(ix,x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3f490fd8) return __kernel_cosf(x,z);
+
+ /* cos(Inf or NaN) is NaN */
+ else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2f(x,y);
+ switch(n&3) {
+ case 0: return __kernel_cosf(y[0],y[1]);
+ case 1: return -__kernel_sinf(y[0],y[1],1);
+ case 2: return -__kernel_cosf(y[0],y[1]);
+ default:
+ return __kernel_sinf(y[0],y[1],1);
+ }
+ }
+}
diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c
index 288008108..be747958e 100644
--- a/stmhal/modpyb.c
+++ b/stmhal/modpyb.c
@@ -193,6 +193,12 @@ STATIC mp_obj_t pyb_standby(void) {
MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby);
+STATIC mp_obj_t pyb_have_cdc(void ) {
+ return MP_BOOL(usb_vcp_is_connected());
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);
+
STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
mp_obj_t *items;
mp_obj_get_array_fixed_n(arg, 4, &items);
@@ -235,6 +241,9 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_usb_mode), (mp_obj_t)&pyb_usb_mode_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_have_cdc), (mp_obj_t)&pyb_have_cdc_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_hid), (mp_obj_t)&pyb_hid_send_report_obj },
+
{ MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj },
@@ -278,8 +287,6 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_Accel), (mp_obj_t)&pyb_accel_type },
#endif
- { MP_OBJ_NEW_QSTR(MP_QSTR_hid), (mp_obj_t)&pyb_hid_send_report_obj },
-
// input
{ MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&pyb_input_obj },
diff --git a/stmhal/pybcdc.h b/stmhal/pybcdc.h
deleted file mode 100644
index 44685a05b..000000000
--- a/stmhal/pybcdc.h
+++ /dev/null
@@ -1,92 +0,0 @@
-"; Windows USB CDC ACM Setup File\r\n"
-"; Based on INF files which were:\r\n"
-"; Copyright (c) 2000 Microsoft Corporation\r\n"
-"; Copyright (C) 2007 Microchip Technology Inc.\r\n"
-"; Likely to be covered by the MLPL as found at:\r\n"
-"; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.\r\n"
-"\r\n"
-"[Version]\r\n"
-"Signature=\"$Windows NT$\"\r\n"
-"Class=Ports\r\n"
-"ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}\r\n"
-"Provider=%MFGNAME%\r\n"
-"LayoutFile=layout.inf\r\n"
-"DriverVer=03/11/2010,5.1.2600.3\r\n"
-"\r\n"
-"[Manufacturer]\r\n"
-"%MFGNAME%=DeviceList, NTamd64\r\n"
-"\r\n"
-"[DestinationDirs]\r\n"
-"DefaultDestDir=12\r\n"
-"\r\n"
-";---------------------------------------------------------------------\r\n"
-"; Windows 2000/XP/Server2003/Vista/Server2008/7 - 32bit Sections\r\n"
-"\r\n"
-"[DriverInstall.nt]\r\n"
-"include=mdmcpq.inf\r\n"
-"CopyFiles=DriverCopyFiles.nt\r\n"
-"AddReg=DriverInstall.nt.AddReg\r\n"
-"\r\n"
-"[DriverCopyFiles.nt]\r\n"
-"usbser.sys,,,0x20\r\n"
-"\r\n"
-"[DriverInstall.nt.AddReg]\r\n"
-"HKR,,DevLoader,,*ntkern\r\n"
-"HKR,,NTMPDriver,,usbser.sys\r\n"
-"HKR,,EnumPropPages32,,\"MsPorts.dll,SerialPortPropPageProvider\"\r\n"
-"\r\n"
-"[DriverInstall.nt.Services]\r\n"
-"AddService=usbser, 0x00000002, DriverService.nt\r\n"
-"\r\n"
-"[DriverService.nt]\r\n"
-"DisplayName=%SERVICE%\r\n"
-"ServiceType=1\r\n"
-"StartType=3\r\n"
-"ErrorControl=1\r\n"
-"ServiceBinary=%12%\\usbser.sys\r\n"
-"\r\n"
-";---------------------------------------------------------------------\r\n"
-"; Windows XP/Server2003/Vista/Server2008/7 - 64bit Sections\r\n"
-"\r\n"
-"[DriverInstall.NTamd64]\r\n"
-"include=mdmcpq.inf\r\n"
-"CopyFiles=DriverCopyFiles.NTamd64\r\n"
-"AddReg=DriverInstall.NTamd64.AddReg\r\n"
-"\r\n"
-"[DriverCopyFiles.NTamd64]\r\n"
-"usbser.sys,,,0x20\r\n"
-"\r\n"
-"[DriverInstall.NTamd64.AddReg]\r\n"
-"HKR,,DevLoader,,*ntkern\r\n"
-"HKR,,NTMPDriver,,usbser.sys\r\n"
-"HKR,,EnumPropPages32,,\"MsPorts.dll,SerialPortPropPageProvider\"\r\n"
-"\r\n"
-"[DriverInstall.NTamd64.Services]\r\n"
-"AddService=usbser, 0x00000002, DriverService.NTamd64\r\n"
-"\r\n"
-"[DriverService.NTamd64]\r\n"
-"DisplayName=%SERVICE%\r\n"
-"ServiceType=1\r\n"
-"StartType=3\r\n"
-"ErrorControl=1\r\n"
-"ServiceBinary=%12%\\usbser.sys\r\n"
-"\r\n"
-";---------------------------------------------------------------------\r\n"
-"; Vendor and Product ID Definitions\r\n"
-"\r\n"
-"[SourceDisksFiles]\r\n"
-"[SourceDisksNames]\r\n"
-"[DeviceList]\r\n"
-"%DESCRIPTION%=DriverInstall, USB\\VID_0483&PID_5740&MI_00, USB\\VID_0483&PID_5740&MI_01\r\n"
-"\r\n"
-"[DeviceList.NTamd64]\r\n"
-"%DESCRIPTION%=DriverInstall, USB\\VID_0483&PID_5740&MI_00, USB\\VID_0483&PID_5740&MI_01\r\n"
-"\r\n"
-";---------------------------------------------------------------------\r\n"
-"; String Definitions\r\n"
-"\r\n"
-"[Strings]\r\n"
-"MFGFILENAME=\"pybcdc\"\r\n"
-"MFGNAME=\"Micro Python\"\r\n"
-"DESCRIPTION=\"Pyboard USB Comm Port\"\r\n"
-"SERVICE=\"USB Serial Driver\"\r\n"
diff --git a/stmhal/pybcdc.inf b/stmhal/pybcdc.inf_template
index eb04b65ce..87cd1467b 100755..100644
--- a/stmhal/pybcdc.inf
+++ b/stmhal/pybcdc.inf_template
@@ -77,10 +77,10 @@ ServiceBinary=%12%\usbser.sys
[SourceDisksFiles]
[SourceDisksNames]
[DeviceList]
-%DESCRIPTION%=DriverInstall, USB\VID_0483&PID_5740&MI_00, USB\VID_0483&PID_5740&MI_01
+%DESCRIPTION%=DriverInstall, USB\VID_${USB_VID}&PID_${USB_PID}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID}&MI_01
[DeviceList.NTamd64]
-%DESCRIPTION%=DriverInstall, USB\VID_0483&PID_5740&MI_00, USB\VID_0483&PID_5740&MI_01
+%DESCRIPTION%=DriverInstall, USB\VID_${USB_VID}&PID_${USB_PID}&MI_00, USB\VID_${USB_VID}&PID_${USB_PID}&MI_01
;---------------------------------------------------------------------
; String Definitions
diff --git a/stmhal/pybstdio.c b/stmhal/pybstdio.c
index d40cebf94..baabfd120 100644
--- a/stmhal/pybstdio.c
+++ b/stmhal/pybstdio.c
@@ -9,7 +9,6 @@
#include "obj.h"
#include "stream.h"
#include "pybstdio.h"
-#include "storage.h"
#include "usb.h"
#include "usart.h"
@@ -50,9 +49,6 @@ int stdin_rx_chr(void) {
return usart_rx_char(pyb_usart_global_debug);
}
__WFI();
- if (storage_needs_flush()) {
- storage_flush();
- }
}
}
diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c
index 298e58a5f..9821e6a92 100644
--- a/stmhal/pyexec.c
+++ b/stmhal/pyexec.c
@@ -21,7 +21,6 @@
#include "pybstdio.h"
#include "readline.h"
#include "pyexec.h"
-#include "storage.h"
#include "usb.h"
#include "build/py/py-version.h"
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index 0dd8c2b61..d64b0c2dd 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -25,6 +25,7 @@ Q(read)
Q(readall)
Q(readline)
Q(write)
+Q(have_cdc)
Q(hid)
Q(time)
Q(rng)
@@ -82,6 +83,7 @@ Q(MODE_EVT_RISING_FALLING)
// for I2C object
Q(I2C)
Q(is_ready)
+Q(scan)
Q(mem_read)
Q(mem_write)
@@ -96,6 +98,7 @@ Q(filtered_xyz)
// for ADC object
Q(ADC)
Q(ADC_all)
+Q(read_timed)
Q(read_channel)
Q(read_core_temp)
Q(read_core_vbat)
diff --git a/stmhal/stm32f4xx_it.c b/stmhal/stm32f4xx_it.c
index aee689d7e..06428a4c4 100644
--- a/stmhal/stm32f4xx_it.c
+++ b/stmhal/stm32f4xx_it.c
@@ -49,6 +49,7 @@
#include "obj.h"
#include "exti.h"
#include "timer.h"
+#include "storage.h"
/** @addtogroup STM32F4xx_HAL_Examples
* @{
@@ -263,6 +264,19 @@ void OTG_XX_WKUP_IRQHandler(void)
{
}*/
+// Handle a flash (erase/program) interrupt.
+void FLASH_IRQHandler(void) {
+ // This calls the real flash IRQ handler, if needed
+ /*
+ uint32_t flash_cr = FLASH->CR;
+ if ((flash_cr & FLASH_IT_EOP) || (flash_cr & FLASH_IT_ERR)) {
+ HAL_FLASH_IRQHandler();
+ }
+ */
+ // This call the storage IRQ handler, to check if the flash cache needs flushing
+ storage_irq_handler();
+}
+
/**
* @brief These functions handle the EXTI interrupt requests.
* @param None
diff --git a/stmhal/storage.c b/stmhal/storage.c
index 98d5ee7e7..0348986f2 100644
--- a/stmhal/storage.c
+++ b/stmhal/storage.c
@@ -16,20 +16,22 @@
#define FLASH_PART1_NUM_BLOCKS (224) // 16k+16k+16k+64k=112k
#define FLASH_MEM_START_ADDR (0x08004000) // sector 1, 16k
+#define FLASH_FLAG_DIRTY (1)
+#define FLASH_FLAG_FORCE_WRITE (2)
+#define FLASH_FLAG_ERASED (4)
static bool flash_is_initialised = false;
-static bool flash_cache_dirty;
+static __IO uint8_t flash_flags = 0;
static uint32_t flash_cache_sector_id;
static uint32_t flash_cache_sector_start;
static uint32_t flash_cache_sector_size;
static uint32_t flash_tick_counter_last_write;
static void flash_cache_flush(void) {
- if (flash_cache_dirty) {
- // sync the cache RAM buffer by writing it to the flash page
- flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
- flash_cache_dirty = false;
- // indicate a clean cache with LED off
- led_state(PYB_LED_R1, 0);
+ if (flash_flags & FLASH_FLAG_DIRTY) {
+ flash_flags |= FLASH_FLAG_FORCE_WRITE;
+ while (flash_flags & FLASH_FLAG_DIRTY) {
+ NVIC->STIR = FLASH_IRQn;
+ }
}
}
@@ -44,9 +46,9 @@ static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) {
flash_cache_sector_start = flash_sector_start;
flash_cache_sector_size = flash_sector_size;
}
- flash_cache_dirty = true;
- // indicate a dirty cache with LED on
- led_state(PYB_LED_R1, 1);
+ flash_flags |= FLASH_FLAG_DIRTY;
+ led_state(PYB_LED_R1, 1); // indicate a dirty cache with LED on
+ flash_tick_counter_last_write = HAL_GetTick();
return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
}
@@ -64,11 +66,17 @@ static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) {
void storage_init(void) {
if (!flash_is_initialised) {
- flash_cache_dirty = false;
+ flash_flags = 0;
flash_cache_sector_id = 0;
- flash_is_initialised = true;
flash_tick_counter_last_write = 0;
+ flash_is_initialised = true;
}
+
+ // Enable the flash IRQ, which is used to also call our storage IRQ handler
+ // It needs to go at a higher priority than all those components that rely on
+ // the flash storage (eg higher than USB MSC).
+ HAL_NVIC_SetPriority(FLASH_IRQn, 1, 1);
+ HAL_NVIC_EnableIRQ(FLASH_IRQn);
}
uint32_t storage_get_block_size(void) {
@@ -79,9 +87,47 @@ uint32_t storage_get_block_count(void) {
return FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS;
}
-bool storage_needs_flush(void) {
- // wait 2 seconds after last write to flush
- return flash_cache_dirty && sys_tick_has_passed(flash_tick_counter_last_write, 2000);
+void storage_irq_handler(void) {
+ if (!(flash_flags & FLASH_FLAG_DIRTY)) {
+ return;
+ }
+
+ // This code uses interrupts to erase the flash
+ /*
+ if (flash_erase_state == 0) {
+ flash_erase_it(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
+ flash_erase_state = 1;
+ return;
+ }
+
+ if (flash_erase_state == 1) {
+ // wait for erase
+ // TODO add timeout
+ #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET)
+ if (!flash_erase_done()) {
+ return;
+ }
+ flash_erase_state = 2;
+ }
+ */
+
+ // This code erases the flash directly, waiting for it to finish
+ if (!(flash_flags & FLASH_FLAG_ERASED)) {
+ flash_erase(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
+ flash_flags |= FLASH_FLAG_ERASED;
+ return;
+ }
+
+ // If not a forced write, wait at least 5 seconds after last write to flush
+ // On file close and flash unmount we get a forced write, so we can afford to wait a while
+ if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || sys_tick_has_passed(flash_tick_counter_last_write, 5000)) {
+ // sync the cache RAM buffer by writing it to the flash page
+ flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
+ // clear the flash flags now that we have a clean cache
+ flash_flags = 0;
+ // indicate a clean cache with LED off
+ led_state(PYB_LED_R1, 0);
+ }
}
void storage_flush(void) {
@@ -167,7 +213,6 @@ bool storage_write_block(const uint8_t *src, uint32_t block) {
uint32_t flash_addr = FLASH_MEM_START_ADDR + (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE;
uint8_t *dest = flash_cache_get_addr_for_write(flash_addr);
memcpy(dest, src, FLASH_BLOCK_SIZE);
- flash_tick_counter_last_write = HAL_GetTick();
return true;
} else {
diff --git a/stmhal/storage.h b/stmhal/storage.h
index 4d153d2f6..ae6c83228 100644
--- a/stmhal/storage.h
+++ b/stmhal/storage.h
@@ -3,7 +3,7 @@
void storage_init(void);
uint32_t storage_get_block_size(void);
uint32_t storage_get_block_count(void);
-bool storage_needs_flush(void);
+void storage_irq_handler(void);
void storage_flush(void);
bool storage_read_block(uint8_t *dest, uint32_t block);
bool storage_write_block(const uint8_t *src, uint32_t block);
diff --git a/stmhal/timer.c b/stmhal/timer.c
index 1e77f0fea..26524fbdd 100644
--- a/stmhal/timer.c
+++ b/stmhal/timer.c
@@ -19,6 +19,7 @@
// the interrupts to be dispatched, so they are all collected here.
//
// TIM3:
+// - flash storage controller, to flush the cache
// - USB CDC interface, interval, to check for new data
// - LED 4, PWM to set the LED intensity
//
@@ -27,6 +28,10 @@
TIM_HandleTypeDef TIM3_Handle;
TIM_HandleTypeDef TIM5_Handle;
+TIM_HandleTypeDef TIM6_Handle;
+
+// Used to divide down TIM3 and periodically call the flash storage IRQ
+static uint32_t tim3_counter = 0;
// TIM3 is set-up for the USB CDC interface
void timer_tim3_init(void) {
@@ -34,8 +39,8 @@ void timer_tim3_init(void) {
__TIM3_CLK_ENABLE();
TIM3_Handle.Instance = TIM3;
- TIM3_Handle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1;
- TIM3_Handle.Init.Prescaler = 84-1;
+ TIM3_Handle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1; // TIM3 fires every USBD_CDC_POLLING_INTERVAL ms
+ TIM3_Handle.Init.Prescaler = 84-1; // for System clock at 168MHz, TIM3 runs at 1MHz
TIM3_Handle.Init.ClockDivision = 0;
TIM3_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_Base_Init(&TIM3_Handle);
@@ -57,6 +62,7 @@ void timer_tim3_deinit(void) {
*/
// TIM5 is set-up for the servo controller
+// This function inits but does not start the timer
void timer_tim5_init(void) {
// TIM5 clock enable
__TIM5_CLK_ENABLE();
@@ -74,10 +80,42 @@ void timer_tim5_init(void) {
HAL_TIM_PWM_Init(&TIM5_Handle);
}
+// Init TIM6 with a counter-overflow at the given frequency (given in Hz)
+// TIM6 is used by the DAC and ADC for auto sampling at a given frequency
+// This function inits but does not start the timer
+void timer_tim6_init(uint freq) {
+ // TIM6 clock enable
+ __TIM6_CLK_ENABLE();
+
+ // Timer runs at SystemCoreClock / 2
+ // Compute the prescaler value so TIM6 triggers at freq-Hz
+ uint32_t period = (SystemCoreClock / 2) / freq;
+ uint32_t prescaler = 1;
+ while (period > 0xffff) {
+ period >>= 1;
+ prescaler <<= 1;
+ }
+
+ // Time base clock configuration
+ TIM6_Handle.Instance = TIM6;
+ TIM6_Handle.Init.Period = period - 1;
+ TIM6_Handle.Init.Prescaler = prescaler - 1;
+ TIM6_Handle.Init.ClockDivision = 0; // unused for TIM6
+ TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
+ HAL_TIM_Base_Init(&TIM6_Handle);
+}
+
// Interrupt dispatch
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &TIM3_Handle) {
USBD_CDC_HAL_TIM_PeriodElapsedCallback();
+
+ // Periodically raise a flash IRQ for the flash storage controller
+ if (tim3_counter++ >= 500 / USBD_CDC_POLLING_INTERVAL) {
+ tim3_counter = 0;
+ NVIC->STIR = FLASH_IRQn;
+ }
+
} else if (htim == &TIM5_Handle) {
servo_timer_irq_callback();
}
diff --git a/stmhal/timer.h b/stmhal/timer.h
index 317b39b3f..06e19bcc8 100644
--- a/stmhal/timer.h
+++ b/stmhal/timer.h
@@ -5,6 +5,8 @@
extern TIM_HandleTypeDef TIM3_Handle;
extern TIM_HandleTypeDef TIM5_Handle;
+extern TIM_HandleTypeDef TIM6_Handle;
void timer_tim3_init(void);
void timer_tim5_init(void);
+void timer_tim6_init(uint freq);
diff --git a/stmhal/usbd_cdc_interface.c b/stmhal/usbd_cdc_interface.c
index c6b6cf23f..b2c85fa4f 100644
--- a/stmhal/usbd_cdc_interface.c
+++ b/stmhal/usbd_cdc_interface.c
@@ -61,6 +61,9 @@ static uint16_t UserRxBufLen = 0; // counts number of valid characters in UserRx
static uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer
static uint16_t UserTxBufPtrIn = 0; // increment this pointer modulo APP_TX_DATA_SIZE when new data is available
static __IO uint16_t UserTxBufPtrOut = 0; // increment this pointer modulo APP_TX_DATA_SIZE when data is drained
+static uint16_t UserTxBufPtrOutShadow = 0; // shadow of above
+static uint8_t UserTxBufPtrWaitCount = 0; // used to implement a timeout waiting for low-level USB driver
+static uint8_t UserTxNeedEmptyPacket = 0; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size
static int user_interrupt_char = VCP_CHAR_NONE;
static void *user_interrupt_data = NULL;
@@ -250,41 +253,62 @@ static int8_t CDC_Itf_Control(uint8_t cmd, uint8_t* pbuf, uint16_t length) {
* @retval None
*/
void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) {
- uint32_t buffptr;
- uint32_t buffsize;
-
- if(UserTxBufPtrOut != UserTxBufPtrIn)
- {
- if(UserTxBufPtrOut > UserTxBufPtrIn) /* rollback */
- {
- buffsize = APP_TX_DATA_SIZE - UserTxBufPtrOut;
+ if (!dev_is_connected) {
+ // CDC device is not connected to a host, so we are unable to send any data
+ return;
}
- else
- {
- buffsize = UserTxBufPtrIn - UserTxBufPtrOut;
+
+ if (UserTxBufPtrOut == UserTxBufPtrIn && !UserTxNeedEmptyPacket) {
+ // No outstanding data to send
+ return;
}
-
- buffptr = UserTxBufPtrOut;
-
- // dpgeorge: For some reason that I don't understand, a packet size of 64 bytes
- // (CDC_DATA_FS_MAX_PACKET_SIZE) does not get through to the USB host until the
- // next packet is sent. To work around this, we just make sure that we never
- // send a packet 64 bytes in length.
- if (buffsize == CDC_DATA_FS_MAX_PACKET_SIZE) {
- buffsize -= 1;
+
+ if (UserTxBufPtrOut != UserTxBufPtrOutShadow) {
+ // We have sent data and are waiting for the low-level USB driver to
+ // finish sending it over the USB in-endpoint.
+ // We have a 15 * 10ms = 150ms timeout
+ if (UserTxBufPtrWaitCount < 15) {
+ PCD_HandleTypeDef *hpcd = hUSBDDevice.pData;
+ USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
+ if (USBx_INEP(CDC_IN_EP & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) {
+ // USB in-endpoint is still reading the data
+ UserTxBufPtrWaitCount++;
+ return;
+ }
+ }
+ UserTxBufPtrOut = UserTxBufPtrOutShadow;
}
-
- USBD_CDC_SetTxBuffer(&hUSBDDevice, (uint8_t*)&UserTxBuffer[buffptr], buffsize);
-
- if(USBD_CDC_TransmitPacket(&hUSBDDevice) == USBD_OK)
- {
- UserTxBufPtrOut += buffsize;
- if (UserTxBufPtrOut == APP_TX_DATA_SIZE)
- {
- UserTxBufPtrOut = 0;
- }
+
+ if (UserTxBufPtrOutShadow != UserTxBufPtrIn || UserTxNeedEmptyPacket) {
+ uint32_t buffptr;
+ uint32_t buffsize;
+
+ if (UserTxBufPtrOutShadow > UserTxBufPtrIn) { // rollback
+ buffsize = APP_TX_DATA_SIZE - UserTxBufPtrOutShadow;
+ } else {
+ buffsize = UserTxBufPtrIn - UserTxBufPtrOutShadow;
+ }
+
+ buffptr = UserTxBufPtrOutShadow;
+
+ USBD_CDC_SetTxBuffer(&hUSBDDevice, (uint8_t*)&UserTxBuffer[buffptr], buffsize);
+
+ if (USBD_CDC_TransmitPacket(&hUSBDDevice) == USBD_OK) {
+ UserTxBufPtrOutShadow += buffsize;
+ if (UserTxBufPtrOutShadow == APP_TX_DATA_SIZE) {
+ UserTxBufPtrOutShadow = 0;
+ }
+ UserTxBufPtrWaitCount = 0;
+
+ // According to the USB specification, a packet size of 64 bytes (CDC_DATA_FS_MAX_PACKET_SIZE)
+ // gets held at the USB host until the next packet is sent. This is because a
+ // packet of maximum size is considered to be part of a longer chunk of data, and
+ // the host waits for all data to arrive (ie, waits for a packet < max packet size).
+ // To flush a packet of exactly max packet size, we need to send a zero-size packet.
+ // See eg http://www.cypress.com/?id=4&rID=92719
+ UserTxNeedEmptyPacket = (buffsize == CDC_DATA_FS_MAX_PACKET_SIZE && UserTxBufPtrOutShadow == UserTxBufPtrIn);
+ }
}
- }
}
/**
@@ -370,11 +394,38 @@ void USBD_CDC_SetInterrupt(int chr, void *data) {
void USBD_CDC_Tx(const char *str, uint32_t len) {
for (int i = 0; i < len; i++) {
- // if the buffer is full, wait until it gets drained, with a timeout of 1000ms (wraparound of tick is taken care of by 2's complement arithmetic)
- uint32_t start = HAL_GetTick();
- while (((UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1)) == UserTxBufPtrOut && HAL_GetTick() - start <= 1000) {
- __WFI(); // enter sleep mode, waiting for interrupt
+ // If the CDC device is not connected to the host then we don't have anyone to receive our data.
+ // The device may become connected in the future, so we should at least try to fill the buffer
+ // and hope that it doesn't overflow by the time the device connects.
+ // If the device is not connected then we should go ahead and fill the buffer straight away,
+ // ignoring overflow. Otherwise, we should make sure that we have enough room in the buffer.
+ if (dev_is_connected) {
+ // If the buffer is full, wait until it gets drained, with a timeout of 500ms
+ // (wraparound of tick is taken care of by 2's complement arithmetic).
+ uint32_t start = HAL_GetTick();
+ while (((UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1)) == UserTxBufPtrOut && HAL_GetTick() - start <= 500) {
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+
+ // Some unused code that makes sure the low-level USB buffer is drained.
+ // Waiting for low-level is handled in USBD_CDC_HAL_TIM_PeriodElapsedCallback.
+ /*
+ start = HAL_GetTick();
+ PCD_HandleTypeDef *hpcd = hUSBDDevice.pData;
+ if (hpcd->IN_ep[0x83 & 0x7f].is_in) {
+ //volatile uint32_t *xfer_count = &hpcd->IN_ep[0x83 & 0x7f].xfer_count;
+ //volatile uint32_t *xfer_len = &hpcd->IN_ep[0x83 & 0x7f].xfer_len;
+ USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
+ while (
+ // *xfer_count < *xfer_len // using this works
+ // (USBx_INEP(3)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) // using this works
+ && HAL_GetTick() - start <= 2000) {
+ __WFI(); // enter sleep mode, waiting for interrupt
+ }
+ }
+ */
}
+
UserTxBuffer[UserTxBufPtrIn] = str[i];
UserTxBufPtrIn = (UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1);
}
diff --git a/stmhal/usbd_msc_storage.c b/stmhal/usbd_msc_storage.c
index f3ecd023d..6ec9abc3d 100644
--- a/stmhal/usbd_msc_storage.c
+++ b/stmhal/usbd_msc_storage.c
@@ -35,6 +35,14 @@
#include "diskio.h"
#include "sdcard.h"
+// These are needed to support removal of the medium, so that the USB drive
+// can be unmounted, and won't be remounted automatically.
+static uint8_t flash_removed = 0;
+
+#if MICROPY_HW_HAS_SDCARD
+static uint8_t sdcard_removed = 0;
+#endif
+
/******************************************************************************/
// Callback functions for when the internal flash is the mass storage device
@@ -83,6 +91,9 @@ int8_t FLASH_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *blo
* @retval Status
*/
int8_t FLASH_STORAGE_IsReady(uint8_t lun) {
+ if (flash_removed) {
+ return -1;
+ }
return 0;
}
@@ -95,6 +106,18 @@ int8_t FLASH_STORAGE_IsWriteProtected(uint8_t lun) {
return 0;
}
+// Remove the lun
+int8_t FLASH_STORAGE_StopUnit(uint8_t lun) {
+ flash_removed = 1;
+ return 0;
+}
+
+int8_t FLASH_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) {
+ // sync the flash so that the cache is cleared and the device can be unplugged/turned off
+ disk_ioctl(0, CTRL_SYNC, NULL);
+ return 0;
+}
+
/**
* @brief Read data from the medium
* @param lun : logical unit number
@@ -132,7 +155,6 @@ int8_t FLASH_STORAGE_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16
}
}
*/
- storage_flush(); // XXX hack for now so that the cache is always flushed
return 0;
}
@@ -150,6 +172,8 @@ const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = {
FLASH_STORAGE_GetCapacity,
FLASH_STORAGE_IsReady,
FLASH_STORAGE_IsWriteProtected,
+ FLASH_STORAGE_StopUnit,
+ FLASH_STORAGE_PreventAllowMediumRemoval,
FLASH_STORAGE_Read,
FLASH_STORAGE_Write,
FLASH_STORAGE_GetMaxLun,
@@ -236,6 +260,9 @@ int8_t SDCARD_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *bl
* @retval Status
*/
int8_t SDCARD_STORAGE_IsReady(uint8_t lun) {
+ if (sdcard_removed) {
+ return -1;
+ }
/*
#ifndef USE_STM3210C_EVAL
@@ -271,6 +298,16 @@ int8_t SDCARD_STORAGE_IsWriteProtected(uint8_t lun) {
return 0;
}
+// Remove the lun
+int8_t SDCARD_STORAGE_StopUnit(uint8_t lun) {
+ sdcard_removed = 1;
+ return 0;
+}
+
+int8_t SDCARD_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) {
+ return 0;
+}
+
/**
* @brief Read data from the medium
* @param lun : logical unit number
@@ -315,6 +352,8 @@ const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = {
SDCARD_STORAGE_GetCapacity,
SDCARD_STORAGE_IsReady,
SDCARD_STORAGE_IsWriteProtected,
+ SDCARD_STORAGE_StopUnit,
+ SDCARD_STORAGE_PreventAllowMediumRemoval,
SDCARD_STORAGE_Read,
SDCARD_STORAGE_Write,
SDCARD_STORAGE_GetMaxLun,
diff --git a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h
index 8423ad775..798bdc99d 100644
--- a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h
+++ b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h
@@ -13,6 +13,11 @@
#define MSC_IN_EP (0x81)
#define MSC_OUT_EP (0x01)
+// Need to define here for usbd_cdc_interface.c (it needs CDC_IN_EP)
+#define CDC_IN_EP (0x83)
+#define CDC_OUT_EP (0x03)
+#define CDC_CMD_EP (0x82)
+
// only CDC_MSC and CDC_HID are available
#define USBD_MODE_CDC (0x01)
#define USBD_MODE_MSC (0x02)
@@ -53,6 +58,8 @@ typedef struct _USBD_STORAGE {
int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint16_t *block_size);
int8_t (* IsReady) (uint8_t lun);
int8_t (* IsWriteProtected) (uint8_t lun);
+ int8_t (* StopUnit)(uint8_t lun);
+ int8_t (* PreventAllowMediumRemoval)(uint8_t lun, uint8_t param0);
int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
int8_t (* GetMaxLun)(void);
diff --git a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c
index 6cb15ba21..aa8c0c80c 100644
--- a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c
+++ b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c
@@ -4,9 +4,6 @@
#define USB_CDC_MSC_CONFIG_DESC_SIZ (98)
#define USB_CDC_HID_CONFIG_DESC_SIZ (100)
#define CDC_IFACE_NUM (1)
-#define CDC_IN_EP (0x83)
-#define CDC_OUT_EP (0x03)
-#define CDC_CMD_EP (0x82)
#define MSC_IFACE_NUM (0)
#define HID_IFACE_NUM_WITH_CDC (0)
#define HID_IFACE_NUM_WITH_MSC (1)
@@ -583,11 +580,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
/*
printf("SU: %x %x %x %x\n", req->bmRequest, req->bRequest, req->wValue, req->wIndex);
+
This is what we get when MSC is IFACE=0 and CDC is IFACE=1,2:
SU: 21 22 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE
SU: 21 20 0 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_LINE_CODING
SU: a1 fe 0 0 -- 0x80 | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; BOT_GET_MAX_LUN; 0; 0
SU: 21 22 3 1 -- USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE; CDC_SET_CONTROL_LINE_STATE
+
+ On a Mac OS X, with MSC then CDC:
+ SU: a1 fe 0 0
+ SU: 21 22 2 1
+ SU: 21 22 3 1
+ SU: 21 20 0 1
*/
switch (req->bmRequest & USB_REQ_TYPE_MASK) {
@@ -723,6 +727,11 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
return USBD_OK;
}
+/* unused
+static uint8_t EP0_TxSent(USBD_HandleTypeDef *pdev) {
+}
+*/
+
static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) {
if((CDC_fops != NULL) && (CDC_ClassData.CmdOpCode != 0xFF)) {
CDC_fops->Control(CDC_ClassData.CmdOpCode, (uint8_t *)CDC_ClassData.data, CDC_ClassData.CmdLength);
@@ -902,8 +911,8 @@ USBD_ClassTypeDef USBD_CDC_MSC_HID = {
USBD_CDC_MSC_HID_DataIn,
USBD_CDC_MSC_HID_DataOut,
NULL, // SOF
- NULL,
- NULL,
+ NULL, // IsoINIncomplete
+ NULL, // IsoOUTIncomplete
USBD_CDC_MSC_HID_GetCfgDesc,
USBD_CDC_MSC_HID_GetCfgDesc,
USBD_CDC_MSC_HID_GetCfgDesc,
diff --git a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c
index af3818d37..60258d64d 100644
--- a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c
+++ b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c
@@ -86,6 +86,7 @@ static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, ui
static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
+static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params);
static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params);
@@ -122,6 +123,11 @@ int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev,
uint8_t lun,
uint8_t *params)
{
+ /*
+ if (params[0] != SCSI_READ10 && params[0] != SCSI_WRITE10) {
+ printf("SCSI_ProcessCmd(lun=%d, params=%x, %x)\n", lun, params[0], params[1]);
+ }
+ */
switch (params[0])
{
@@ -137,7 +143,7 @@ int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev,
return SCSI_StartStopUnit(pdev, lun, params);
case SCSI_ALLOW_MEDIUM_REMOVAL:
- return SCSI_StartStopUnit(pdev, lun, params);
+ return SCSI_AllowMediumRemoval(pdev, lun, params);
case SCSI_MODE_SENSE6:
return SCSI_ModeSense6 (pdev, lun, params);
@@ -442,6 +448,31 @@ static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t
{
USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassData;
hmsc->bot_data_length = 0;
+
+ // On Mac OS X, when the device is ejected a SCSI_START_STOP_UNIT command is sent.
+ // params[1]==0 means stop, param[1]==1 seems to be something else (happens after the
+ // device is plugged in and mounted for some time, probably a keep alive).
+ // If we get a stop, we must really stop the device so that the Mac does not
+ // automatically remount it.
+ if (params[1] == 0) {
+ ((USBD_StorageTypeDef *)pdev->pUserData)->StopUnit(lun);
+ }
+
+ return 0;
+}
+
+/**
+* @brief SCSI_AllowMediumRemoval
+* Process Allow Medium Removal command
+* @param lun: Logical unit number
+* @param params: Command parameters
+* @retval status
+*/
+static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+ USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassData;
+ hmsc->bot_data_length = 0;
+ ((USBD_StorageTypeDef *)pdev->pUserData)->PreventAllowMediumRemoval(lun, params[0]);
return 0;
}
diff --git a/tests/basics/builtin-bin.py b/tests/basics/builtin-bin.py
new file mode 100644
index 000000000..f6b6079de
--- /dev/null
+++ b/tests/basics/builtin-bin.py
@@ -0,0 +1,12 @@
+# test builtin bin function
+
+print(bin(1))
+print(bin(-1))
+print(bin(15))
+print(bin(-15))
+
+print(bin(12345))
+print(bin(0b10101))
+
+print(bin(12345678901234567890))
+print(bin(0b10101010101010101010))
diff --git a/tests/basics/builtin-hex.py b/tests/basics/builtin-hex.py
new file mode 100644
index 000000000..7d1c98a7a
--- /dev/null
+++ b/tests/basics/builtin-hex.py
@@ -0,0 +1,12 @@
+# test builtin hex function
+
+print(hex(1))
+print(hex(-1))
+print(hex(15))
+print(hex(-15))
+
+print(hex(12345))
+print(hex(0x12345))
+
+print(hex(12345678901234567890))
+print(hex(0x12345678901234567890))
diff --git a/tests/basics/builtin-oct.py b/tests/basics/builtin-oct.py
new file mode 100644
index 000000000..d8ba8e434
--- /dev/null
+++ b/tests/basics/builtin-oct.py
@@ -0,0 +1,12 @@
+# test builtin oct function
+
+print(oct(1))
+print(oct(-1))
+print(oct(15))
+print(oct(-15))
+
+print(oct(12345))
+print(oct(0o12345))
+
+print(oct(12345678901234567890))
+print(oct(0o12345670123456701234))
diff --git a/tests/basics/fun-callstar.py b/tests/basics/fun-callstar.py
index e19acb349..255563b26 100644
--- a/tests/basics/fun-callstar.py
+++ b/tests/basics/fun-callstar.py
@@ -31,5 +31,3 @@ a.foo(1, 2, *[100])
# Iterator
a.foo(*range(3))
-
-print('flush') # so that it works on pyboard...
diff --git a/tests/basics/fun-defargs.py b/tests/basics/fun-defargs.py
index 51516c736..0666b8c49 100644
--- a/tests/basics/fun-defargs.py
+++ b/tests/basics/fun-defargs.py
@@ -18,5 +18,3 @@ try:
fun2(1, 2, 3, 4)
except TypeError:
print("TypeError")
-
-print('flush') # so that it works on pyboard...
diff --git a/tests/basics/memoryerror.py b/tests/basics/memoryerror.py
index e9aa97d85..b4be420c3 100644
--- a/tests/basics/memoryerror.py
+++ b/tests/basics/memoryerror.py
@@ -1,11 +1,6 @@
-# this test for MemoryError can be difficult to reproduce
-# on different machine configurations (notably Travis CI)
-# so we disable it
-# TODO is there a way of testing that we are on Travis CI?
-if False:
- l = list(range(10000))
- try:
- 100000000 * l
- except MemoryError:
- print('MemoryError')
- print(len(l), l[0], l[-1])
+l = list(range(10000))
+try:
+ 100000000 * l
+except MemoryError:
+ print('MemoryError')
+print(len(l), l[0], l[-1])
diff --git a/tests/bytecode/README.md b/tests/bytecode/README.md
index 85e348ded..0d5245cb7 100644
--- a/tests/bytecode/README.md
+++ b/tests/bytecode/README.md
@@ -5,7 +5,7 @@ You need to first build the 'cpy' executable in the directory micropython/unix-c
This executable is a minimal version of Micro Python which compiles a single source
file and outputs the corresponding byte code.
-The output of Micro Python is checked against CPython 3.3.
+The output of Micro Python is checked against CPython 3.4.
To run the tests use:
diff --git a/tests/run-tests b/tests/run-tests
index 554f5134c..bd6e50bbd 100755
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -15,6 +15,9 @@ else:
CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3')
MP_PY = '../unix/micropython'
+# Set of tests that we shouldn't run under Travis CI
+skip_travis_tests = set(['basics/memoryerror.py'])
+
def rm_f(fname):
if os.path.exists(fname):
os.remove(fname)
@@ -36,8 +39,12 @@ if test_on_pyboard:
pyb = pyboard.Pyboard('/dev/ttyACM0')
pyb.enter_raw_repl()
+running_under_travis = os.environ.get('TRAVIS', 'false') == 'true'
+
for test_file in tests:
- test_name = os.path.splitext(os.path.basename(test_file))[0]
+ if running_under_travis and test_file in skip_travis_tests:
+ print("skip ", test_file)
+ continue
# run CPython
try:
@@ -64,15 +71,20 @@ for test_file in tests:
testcase_count += len(output_expected.splitlines())
+ test_basename = os.path.basename(test_file)
+ test_name = os.path.splitext(test_basename)[0]
+ filename_expected = test_basename + ".exp"
+ filename_mupy = test_basename + ".out"
+
if output_expected == output_mupy:
print("pass ", test_file)
passed_count += 1
- rm_f(os.path.basename(test_file + ".exp"))
- rm_f(os.path.basename(test_file + ".out"))
+ rm_f(filename_expected)
+ rm_f(filename_mupy)
else:
- with open(os.path.basename(test_file + ".exp"), "w") as f:
+ with open(filename_expected, "w") as f:
f.write(str(output_expected, "ascii"))
- with open(os.path.basename(test_file + ".out"), "w") as f:
+ with open(filename_mupy, "w") as f:
f.write(str(output_mupy, "ascii"))
print("FAIL ", test_file)
failed_tests.append(test_name)
diff --git a/tools/file2h.py b/tools/file2h.py
new file mode 100644
index 000000000..2a04ae22b
--- /dev/null
+++ b/tools/file2h.py
@@ -0,0 +1,30 @@
+# Reads in a text file, and performs the necessary escapes so that it
+# can be #included as a static string like:
+# static const char string_from_textfile[] =
+# #include "build/textfile.h"
+# ;
+# This script simply prints the escaped string straight to stdout
+
+from __future__ import print_function
+
+import sys
+
+# Can either be set explicitly, or left blank to auto-detect
+# Except auto-detect doesn't work because the file has been passed
+# through Python text processing, which makes all EOL a \n
+line_end = '\\r\\n'
+
+if __name__ == "__main__":
+ filename = sys.argv[1]
+ for line in open(filename, 'r').readlines():
+ if not line_end:
+ for ending in ('\r\n', '\r', '\n'):
+ if line.endswith(ending):
+ line_end = ending.replace('\r', '\\r').replace('\n', '\\n')
+ break
+ if not line_end:
+ raise Exception("Couldn't auto-detect line-ending of %s" % filename)
+ line = line.rstrip('\r\n')
+ line = line.replace('\\', '\\\\')
+ line = line.replace('"', '\\"')
+ print('"%s%s"' % (line, line_end))
diff --git a/tools/insert-usb-ids.py b/tools/insert-usb-ids.py
new file mode 100644
index 000000000..42303da8b
--- /dev/null
+++ b/tools/insert-usb-ids.py
@@ -0,0 +1,36 @@
+# Reads the USB VID and PID from the file specifed by sys.arg[1] and then
+# inserts those values into the template file specified by sys.argv[2],
+# printing the result to stdout
+
+from __future__ import print_function
+
+import sys
+import re
+import string
+
+def parse_usb_ids(filename):
+ rv = dict()
+ if filename == 'usbd_desc_cdc_msc.c':
+ for line in open(filename).readlines():
+ line = line.rstrip('\r\n')
+ match = re.match('^#define\s+(\w+)\s+0x([0-9A-Fa-f]+)$', line)
+ if match:
+ if match.group(1) == 'USBD_VID':
+ rv['USB_VID'] = match.group(2)
+ elif match.group(1) == 'USBD_PID':
+ rv['USB_PID'] = match.group(2)
+ if 'USB_VID' in rv and 'USB_PID' in rv:
+ break
+ else:
+ raise Exception("Don't (yet) know how to parse USB IDs from %s" % filename)
+ for k in ('USB_PID', 'USB_VID'):
+ if k not in rv:
+ raise Exception("Unable to parse %s from %s" % (k, filename))
+ return rv
+
+if __name__ == "__main__":
+ usb_ids_file = sys.argv[1]
+ template_file = sys.argv[2]
+ replacements = parse_usb_ids(usb_ids_file)
+ for line in open(template_file, 'r').readlines():
+ print(string.Template(line).safe_substitute(replacements), end='')
diff --git a/unix/Makefile b/unix/Makefile
index ac1baf3d0..07a75f7ad 100644
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -20,6 +20,16 @@ else
LDFLAGS = $(LDFLAGS_MOD) -lm -Wl,-Map=$@.map,--cref
endif
+ifeq ($(MICROPY_FORCE_32BIT),1)
+CFLAGS += -m32
+LDFLAGS += -m32
+ifeq ($(MICROPY_MOD_FFI),1)
+ifeq ($(UNAME_S),Linux)
+CFLAGS_MOD += -I/usr/include/i686-linux-gnu
+endif
+endif
+endif
+
ifeq ($(MICROPY_USE_READLINE),1)
CFLAGS_MOD += -DMICROPY_USE_READLINE=1
LDFLAGS_MOD += -lreadline
diff --git a/unix/mpconfigport.mk b/unix/mpconfigport.mk
index bfb01a71f..352d01067 100644
--- a/unix/mpconfigport.mk
+++ b/unix/mpconfigport.mk
@@ -1,5 +1,8 @@
# Enable/disable modules and 3rd-party libs to be included in interpreter
+# Build 32-bit binaries on a 64-bit host
+MICROPY_FORCE_32BIT = 0
+
# Linking with GNU readline causes binary to be licensed under GPL
MICROPY_USE_READLINE = 1