-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add busio.~~I2CSlave~~ (I2CPeripheral, later I2CTarget) #1064
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks for working on this! 7k bytes seems like a lot! Split it into its own module and list it here: https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/mpconfigport.h#L221 |
Version 2
Two things I didn't know where to put: I2CSlaveRequest has 3 readonly properties: address, is_read and is_restart. I've implemented these using property getters. #define MP_DEFINE_CONST_PROP_GET(obj_name, fun_name) \
const mp_obj_fun_builtin_fixed_t fun_name##_obj = {{&mp_type_fun_builtin_1}, .fun._1 = fun_name}; \
const mp_obj_property_t obj_name = { \
.base.type = &mp_type_property, \
.proxy = {(mp_obj_t)&fun_name##_obj, \
(mp_obj_t)&mp_const_none_obj, \
(mp_obj_t)&mp_const_none_obj}, } I've made this function to honour Ctrl-C in the REPL. Where should I put it? static inline bool mp_hal_is_interrupted(void) {
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP
#endif
return MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
} |
uint32_t sda_pinmux = 0; | ||
uint32_t scl_pinmux = 0; | ||
Sercom *samd_i2c_get_sercom(const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, | ||
uint8_t *sercom_index, uint32_t *sda_pinmux, uint32_t *scl_pinmux) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could go into the peripherals library. Up to you if you want to move it.
I'd put the macro here: https://github.com/adafruit/circuitpython/blob/master/py/obj.h#L295 I'd put the helper method here: https://github.com/adafruit/circuitpython/blob/master/lib/utils/interrupt_char.c#L49 Thanks! |
Version 3
These ran out of space:
|
The feather_huzzah build choked on my bool:
I'll include stdbool.h in the next version when the out of flash solution is decided. |
Hey @notro, mind adding a shared define such as SPECIALTY_BOARD that will trigger the exclusion of I2CSlave? Those four builds are full because they include a bunch of library code for their specific uses so it doesn't need to be loaded into RAM. |
Is this what you had in mind? #if defined(__SAMD51G19A__) || defined(__SAMD51G18A__)
#define AUDIOBUSIO_MODULE
#else
#define AUDIOBUSIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiobusio), (mp_obj_t)&audiobusio_module },
#endif
+ #ifdef SPECIALTY_BOARD
+ #define I2CSLAVE_MODULE
+ #else
+ #define I2CSLAVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_i2cslave), (mp_obj_t)&i2cslave_module },
+ #endif
+
#ifndef EXTRA_BUILTIN_MODULES
#define EXTRA_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module }, \
AUDIOBUSIO_MODULE \
{ MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }, \
+ I2CSLAVE_MODULE \
{ MP_OBJ_NEW_QSTR(MP_QSTR_rotaryio), (mp_obj_t)&rotaryio_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module }
#endif
#define EXPRESS_BOARD |
How about just I am also surprised it is 7kB. Have you looked at the Besides the map, this command is useful for figuring out what's taking up space in the the image:
And this script called on the
|
Yes it's just the C code. This didn't make much sense to me, but here they are: |
Thanks, that's very helpful. What I see is that the double-precision floating point library has been dragged in, because I see They were brought in probably because of this code:
which is mixing See #342 and #343 for an example of what I did to remove the |
Thanks @dhalbert for catching this. Changing timeout to timeout_ms and always use an integer avoids pulling in the library and the size increase is now ~2.8k: #if MICROPY_PY_BUILTINS_FLOAT
- float timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+ float f = mp_obj_get_float(args[ARG_timeout].u_obj) * 1000;
+ int timeout_ms = (int)f;
#else
- int timeout = mp_obj_get_int(args[ARG_timeout].u_obj);
+ int timeout_ms = mp_obj_get_int(args[ARG_timeout].u_obj) * 1000;
#endif I discovered a problem with the // Check to see if we've been CTRL-C'ed by autoreload or the user.
bool mp_hal_is_interrupted(void) {
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP
#endif
return MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
} If I press Ctrl-C once in the REPL, it will return
I see that the same happens when |
So the Ctrl-C problem is of recent origin: #1092 Back to flash overflow. The Hallowing builds now, but these don't:
@tannewt suggested a One difference is whether i2cslave is built by default or not. |
One question is whether someone who needs I2C slave is savvy enough to know how to do builds. Are you thinking of an SPI slave also? If we turn it on in general, I'd turn it on for the general purpose Express boards and all M4 boards (but I know it's not implemented there yet). Leave it off for the non-express boards and turn it off for CPX and the |
No. The reason I'm doing I2CSlave is so I can emulate an RTC (ds1307) and PMIC (axp209) for use with a Raspberry Pi. The Pi lacks a clock and a power controller. |
Version 4
|
I have a problem with the MP_ETIMEDOUT value. I expect it to be 110 but it is 116: This is the C code: if (timeout_ms > 0) {
mp_raise_OSError(MP_ETIMEDOUT);
} This is the result:
CPython value:
From py/mperrno.h (MICROPY_USE_INTERNAL_ERRNO is 0):
Does anyone know where the file |
In This already came up in micropython#976. We could set |
Thanks @dhalbert, so it's a OS issue then. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the huzzah build is missing in include. Everything else looks good to go.
It's not obvious to me what to include. lib/utils/interrupt_char.c #include "py/obj.h"
#include "py/mpstate.h"
#if MICROPY_KBD_EXCEPTION
<snip>
// Check to see if we've been CTRL-C'ed by autoreload or the user.
bool mp_hal_is_interrupted(void) {
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP
#endif
return MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
}
#endif ports/esp8266/mpconfigport.h extern void ets_event_poll(void);
#define MICROPY_EVENT_POLL_HOOK {ets_event_poll();}
#define MICROPY_VM_HOOK_COUNT (10)
#define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT;
#define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \
vm_hook_divisor = MICROPY_VM_HOOK_COUNT; \
extern void ets_loop_iter(void); \
ets_loop_iter(); \
}
#define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL
#define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL Build error:
|
Ugh ya. Some files simply don't include what they use. That's why I thought it would be simple. Here I think we should move the VM_HOOK part back into the wait loops. ESP doesn't use that code anyway so it should fix the compile. |
Ok, I'll take it out of mp_hal_is_interrupted(). Is it really necessary to check that the macro is defined: #ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP
#endif When we have this in // Hook for the VM during the opcode loop (but only after jump opcodes)
#ifndef MICROPY_VM_HOOK_LOOP
#define MICROPY_VM_HOOK_LOOP
#endif It looks like I can just do this: while (common_hal_time_monotonic() < timeout_end) {
MICROPY_VM_HOOK_LOOP
if (mp_hal_is_interrupted()) {
break;
} Actually that's how it's used in pending_exception_check:
MICROPY_VM_HOOK_LOOP
|
It might just be a legacy thing. Feel free to remove the ifdef. |
It will be shared with I2CSlave.
This adds support for SAMD acting as a I2C slave in polled mode.
Version 5
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thank you!
Thanks for your review @tannewt! |
This adds a busio.I2CSlave binding and implements it on samd.
M4 is not tested yet, I want to see if the API needs to change before spending time on that.
I didn't use asf4 because it lacked smbus support (and the code looked fragile wrt misbehaving masters).
I2CSlaveRequest has 3 readonly properties and I wonder if there's a simpler way to implement those than to use accessor functions as I have done.
How do I make I2CSlave optional on other ports? Use a macro?
Example use:
Use from Linux:
I've started on a SMBUS slave library that also contains tests for I2CSlave: https://github.com/notro/cp-smbusslave
It supports non-standard sequential modes which makes it useful with some i2c devices.
Example use:
Currently there are 3 emulated devices:
The first two are potentially useful with a Raspberry Pi since it lacks a hw clock and an ADC.
The i2c hw on the Pi doesn't support clock stretching so it's necessary to use bitbanging.
/boot/config.txt