@ -58,9 +58,18 @@
// Open drain behaviour is simulated.
# define GPIO_IS_OPEN_DRAIN(id) (machine_pin_open_drain_mask & (1 << (id)))
# ifndef MICROPY_HW_PIN_RESERVED
# define MICROPY_HW_PIN_RESERVED(i) (0)
# endif
typedef struct _machine_pin_obj_t {
mp_obj_base_t base ;
uint32_t id ;
uint8_t id ;
# if MICROPY_HW_PIN_CYW43_COUNT
bool is_cyw43 ;
bool is_output ;
bool last_output_value ;
# endif
} machine_pin_obj_t ;
typedef struct _machine_pin_irq_obj_t {
@ -104,9 +113,60 @@ STATIC const machine_pin_obj_t machine_pin_obj[NUM_BANK0_GPIOS] = {
{ { & machine_pin_type } , 29 } ,
} ;
# if MICROPY_HW_PIN_CYW43_COUNT
# include "lib/cyw43-driver/src/cyw43.h"
# define CYW43_PIN_NAME_PREFIX "WL_GPIO"
STATIC machine_pin_obj_t cyw43_pin_obj [ MICROPY_HW_PIN_CYW43_COUNT ] ;
# endif
# define LED_PIN_NAME "LED"
# ifndef MICROPY_HW_PIN_ENABLE_LED_PIN
# if defined(MICROPY_HW_PIN_CYW43_LED_PIN_NUM) || defined(PICO_DEFAULT_LED_PIN)
# define MICROPY_HW_PIN_ENABLE_LED_PIN 1
# endif
# endif
# ifdef MICROPY_HW_PIN_ENABLE_LED_PIN
# ifdef MICROPY_HW_PIN_CYW43_LED_PIN_NUM
STATIC machine_pin_obj_t * led_pin_obj = & cyw43_pin_obj [ MICROPY_HW_PIN_CYW43_LED_PIN_NUM ] ;
# elif defined(MICROPY_HW_PIN_LED_PIN_NUM)
STATIC machine_pin_obj_t * led_pin_obj = & machine_pin_obj [ MICROPY_HW_PIN_LED_PIN_NUM ] ;
# elif defined(PICO_DEFAULT_LED_PIN)
STATIC const machine_pin_obj_t * led_pin_obj = & machine_pin_obj [ PICO_DEFAULT_LED_PIN ] ;
# else
# error MICROPY_HW_PIN_ENABLE_LED_PIN defined but there is no LED pin
# endif
# endif
// Mask with "1" indicating that the corresponding pin is in simulated open-drain mode.
uint32_t machine_pin_open_drain_mask ;
# if MICROPY_HW_PIN_CYW43_COUNT
STATIC inline bool is_cyw43_pin ( __unused const machine_pin_obj_t * self ) {
return self - > is_cyw43 ;
}
# else
# define is_cyw43_pin(x) false
# endif
# if MICROPY_HW_PIN_CYW43_COUNT
STATIC inline void update_cyw43_value ( __unused machine_pin_obj_t * self , bool value ) {
if ( value ! = self - > last_output_value | | ! self - > is_output ) {
cyw43_gpio_set ( & cyw43_state , self - > id , value ) ;
}
self - > last_output_value = value ;
}
# endif
# if MICROPY_HW_PIN_CYW43_COUNT
STATIC inline bool get_cyw43_value ( __unused machine_pin_obj_t * self ) {
bool value = false ;
cyw43_gpio_get ( & cyw43_state , self - > id , & value ) ;
return value ;
}
# endif
STATIC void gpio_irq ( void ) {
for ( int i = 0 ; i < 4 ; + + i ) {
uint32_t intr = iobank0_hw - > intr [ i ] ;
@ -129,15 +189,24 @@ STATIC void gpio_irq(void) {
void machine_pin_init ( void ) {
memset ( MP_STATE_PORT ( machine_pin_irq_obj ) , 0 , sizeof ( MP_STATE_PORT ( machine_pin_irq_obj ) ) ) ;
irq_set_exclusive _handler ( IO_IRQ_BANK0 , gpio_irq ) ;
irq_add_shared _handler ( IO_IRQ_BANK0 , gpio_irq , PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY ) ;
irq_set_enabled ( IO_IRQ_BANK0 , true ) ;
# if MICROPY_HW_PIN_CYW43_COUNT
for ( uint i = 0 ; i < count_of ( cyw43_pin_obj ) ; i + + ) {
cyw43_pin_obj [ i ] . id = i ;
cyw43_pin_obj [ i ] . base . type = & machine_pin_type ;
cyw43_pin_obj [ i ] . is_cyw43 = true ;
}
# endif
}
void machine_pin_deinit ( void ) {
for ( int i = 0 ; i < NUM_BANK0_GPIOS ; + + i ) {
if ( MICROPY_HW_PIN_RESERVED ( i ) ) {
continue ;
}
gpio_set_irq_enabled ( i , GPIO_IRQ_ALL , false ) ;
}
irq_set_enabled ( IO_IRQ_BANK0 , false ) ;
irq_remove_handler ( IO_IRQ_BANK0 , gpio_irq ) ;
}
@ -145,45 +214,112 @@ STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_prin
machine_pin_obj_t * self = self_in ;
uint funcsel = GPIO_GET_FUNCSEL ( self - > id ) ;
qstr mode_qst ;
if ( funcsel = = GPIO_FUNC_SIO ) {
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
mode_qst = MP_QSTR_OPEN_DRAIN ;
} else if ( GPIO_IS_OUT ( self - > id ) ) {
mode_qst = MP_QSTR_OUT ;
if ( ! is_cyw43_pin ( self ) ) {
if ( funcsel = = GPIO_FUNC_SIO ) {
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
mode_qst = MP_QSTR_OPEN_DRAIN ;
} else if ( GPIO_IS_OUT ( self - > id ) ) {
mode_qst = MP_QSTR_OUT ;
} else {
mode_qst = MP_QSTR_IN ;
}
} else {
mode_qst = MP_QSTR_IN ;
mode_qst = MP_QSTR_ALT ;
}
mp_printf ( print , " Pin(%u, mode=%q " , self - > id , mode_qst ) ;
bool pull_up = false ;
if ( GPIO_IS_PULL_UP ( self - > id ) ) {
mp_printf ( print , " , pull=%q " , MP_QSTR_PULL_UP ) ;
pull_up = true ;
}
if ( GPIO_IS_PULL_DOWN ( self - > id ) ) {
if ( pull_up ) {
mp_printf ( print , " |%q " , MP_QSTR_PULL_DOWN ) ;
} else {
mp_printf ( print , " , pull=%q " , MP_QSTR_PULL_DOWN ) ;
}
}
if ( funcsel ! = GPIO_FUNC_SIO ) {
mp_printf ( print , " , alt=%u " , funcsel ) ;
}
} else {
mode_qst = MP_QSTR_ALT ;
# if MICROPY_HW_PIN_CYW43_COUNT
mode_qst = self - > is_output ? MP_QSTR_OUT : MP_QSTR_IN ;
mp_printf ( print , " Pin(%s%u, mode=%q " , CYW43_PIN_NAME_PREFIX , self - > id , mode_qst ) ;
# endif
}
mp_printf ( print , " ) " ) ;
}
enum {
ARG_mode , ARG_pull , ARG_value , ARG_alt
} ;
static const mp_arg_t allowed_args [ ] = {
{ MP_QSTR_mode , MP_ARG_OBJ , { . u_rom_obj = MP_ROM_NONE } } ,
{ MP_QSTR_pull , MP_ARG_OBJ , { . u_rom_obj = MP_ROM_NONE } } ,
{ MP_QSTR_value , MP_ARG_KW_ONLY | MP_ARG_OBJ , { . u_rom_obj = MP_ROM_NONE } } ,
{ MP_QSTR_alt , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = GPIO_FUNC_SIO } } ,
} ;
# if MICROPY_HW_PIN_CYW43_COUNT
// pin.init(mode, pull=None, *, value=None, alt=FUNC_SIO)
STATIC mp_obj_t machine_pin_cyw43_obj_init_helper ( machine_pin_obj_t * self , size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
mp_arg_val_t args [ MP_ARRAY_SIZE ( allowed_args ) ] ;
mp_arg_parse_all ( n_args , pos_args , kw_args , MP_ARRAY_SIZE ( allowed_args ) , allowed_args , args ) ;
if ( args [ ARG_pull ] . u_obj ! = mp_const_none ) {
int pull = mp_obj_get_int ( args [ ARG_pull ] . u_obj ) ;
if ( pull ) {
mp_raise_ValueError ( " Pulls are not supported for this pin " ) ;
}
}
if ( args [ ARG_alt ] . u_int ! = GPIO_FUNC_SIO ) {
mp_raise_ValueError ( " Alternate functions are not supported for this pin " ) ;
}
mp_printf ( print , " Pin(%u, mode=%q " , self - > id , mode_qst ) ;
bool pull_up = false ;
if ( GPIO_IS_PULL_UP ( self - > id ) ) {
mp_printf ( print , " , pull=%q " , MP_QSTR_PULL_UP ) ;
pull_up = true ;
int value = - 1 ;
if ( args [ ARG_value ] . u_obj ! = mp_const_none ) {
value = mp_obj_is_true ( args [ ARG_value ] . u_obj ) ;
}
if ( GPIO_IS_PULL_DOWN ( self - > id ) ) {
if ( pull_up ) {
mp_printf ( print , " |%q " , MP_QSTR_PULL_DOWN ) ;
if ( args [ ARG_mode ] . u_obj ! = mp_const_none ) {
mp_int_t mode = mp_obj_get_int ( args [ ARG_mode ] . u_obj ) ;
if ( mode = = GPIO_MODE_IN ) {
if ( self - > is_output ) {
// todo need to disable output
}
self - > is_output = false ;
} else if ( mode = = GPIO_MODE_OUT ) {
if ( ! self - > is_output ) {
// todo need to enable output
// for now we just set the value
if ( value = = - 1 ) {
value = self - > last_output_value ;
}
self - > last_output_value = ! self - > last_output_value ; // defeat shortcircuit
update_cyw43_value ( self , value ) ;
self - > is_output = true ;
}
} else {
mp_printf ( print , " , pull=%q " , MP_QSTR_PULL_DOWN ) ;
mp_raise_ValueError ( " only Pin.OUT and Pin.IN are supported for this pin " ) ;
}
}
if ( funcsel ! = GPIO_FUNC_SIO ) {
mp_printf ( print , " , alt=%u " , funcsel ) ;
if ( value ! = - 1 ) {
if ( self - > is_output ) {
update_cyw43_value ( self , value ) ;
} else {
// figure if you pass a value to IN it should still remember it (this is what regular GPIO does)
self - > last_output_value = value ;
}
}
mp_printf ( print , " ) " ) ;
return mp_const_none ;
}
# endif
// pin.init(mode, pull=None, *, value=None, alt=FUNC_SIO)
STATIC mp_obj_t machine_pin_obj_init_helper ( const machine_pin_obj_t * self , size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
enum { ARG_mode , ARG_pull , ARG_value , ARG_alt } ;
static const mp_arg_t allowed_args [ ] = {
{ MP_QSTR_mode , MP_ARG_OBJ , { . u_rom_obj = MP_ROM_NONE } } ,
{ MP_QSTR_pull , MP_ARG_OBJ , { . u_rom_obj = MP_ROM_NONE } } ,
{ MP_QSTR_value , MP_ARG_KW_ONLY | MP_ARG_OBJ , { . u_rom_obj = MP_ROM_NONE } } ,
{ MP_QSTR_alt , MP_ARG_KW_ONLY | MP_ARG_INT , { . u_int = GPIO_FUNC_SIO } } ,
} ;
// parse args
mp_arg_val_t args [ MP_ARRAY_SIZE ( allowed_args ) ] ;
@ -216,7 +352,6 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
pull = mp_obj_get_int ( args [ ARG_pull ] . u_obj ) ;
}
gpio_set_pulls ( self - > id , pull & GPIO_PULL_UP , pull & GPIO_PULL_DOWN ) ;
return mp_const_none ;
}
@ -224,21 +359,57 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
mp_obj_t mp_pin_make_new ( const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
mp_arg_check_num ( n_args , n_kw , 1 , MP_OBJ_FUN_ARGS_MAX , true ) ;
// get the wanted pin object
int wanted_pin = mp_obj_get_int ( args [ 0 ] ) ;
if ( ! ( 0 < = wanted_pin & & wanted_pin < MP_ARRAY_SIZE ( machine_pin_obj ) ) ) {
mp_raise_ValueError ( " invalid pin " ) ;
}
const machine_pin_obj_t * self = & machine_pin_obj [ wanted_pin ] ;
const machine_pin_obj_t * self = NULL ;
if ( mp_obj_is_str ( args [ 0 ] ) ) {
const char * name = mp_obj_str_get_str ( args [ 0 ] ) ;
# if MICROPY_HW_PIN_ENABLE_LED_PIN
if ( ! strcmp ( name , LED_PIN_NAME ) ) {
self = led_pin_obj ;
}
# endif
# if MICROPY_HW_PIN_CYW43_COUNT
static_assert ( MICROPY_HW_PIN_CYW43_COUNT < 10 , " " ) ; // makes parsing name easy!
if ( ! self & & ! strncmp ( name , CYW43_PIN_NAME_PREFIX , strlen ( CYW43_PIN_NAME_PREFIX ) ) & & strlen ( name ) = = strlen ( CYW43_PIN_NAME_PREFIX ) + 1 ) {
int num = name [ strlen ( CYW43_PIN_NAME_PREFIX ) ] - ' 0 ' ;
if ( num < MICROPY_HW_PIN_CYW43_COUNT ) {
self = & cyw43_pin_obj [ num ] ;
}
}
# endif
if ( ! self ) {
mp_raise_msg_varg ( & mp_type_ValueError , MP_ERROR_TEXT ( " Unknown named pin \" %s \" " ) , name ) ;
}
}
if ( ! self ) {
// get the wanted pin object
int wanted_pin = mp_obj_get_int ( args [ 0 ] ) ;
if ( ! ( 0 < = wanted_pin & & wanted_pin < MP_ARRAY_SIZE ( machine_pin_obj ) ) ) {
mp_raise_ValueError ( " invalid pin " ) ;
}
self = & machine_pin_obj [ wanted_pin ] ;
}
// note we have different init args based on the type of pin. so Pin("LED", Pin.OUT) may not always make sense
if ( ! is_cyw43_pin ( self ) ) {
if ( n_args > 1 | | n_kw > 0 ) {
// pin mode given, so configure this GPIO
mp_map_t kw_args ;
mp_map_init_fixed_table ( & kw_args , n_kw , args + n_args ) ;
machine_pin_obj_init_helper ( self , n_args - 1 , args + 1 , & kw_args ) ;
}
return MP_OBJ_FROM_PTR ( self ) ;
}
# if MICROPY_HW_PIN_CYW43_COUNT
if ( n_args > 1 | | n_kw > 0 ) {
// pin mode given, so configure this GPIO
mp_map_t kw_args ;
mp_map_init_fixed_table ( & kw_args , n_kw , args + n_args ) ;
machine_pin_obj_init_helper ( self , n_args - 1 , args + 1 , & kw_args ) ;
// The regular Pins are const, but the CYW43 pins are mutable.
machine_pin_obj_t * mutable_self = ( machine_pin_obj_t * ) self ;
machine_pin_cyw43_obj_init_helper ( mutable_self , n_args - 1 , args + 1 , & kw_args ) ;
}
return MP_OBJ_FROM_PTR ( self ) ;
# endif
}
// fast method for getting/setting pin value
@ -247,23 +418,39 @@ STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c
machine_pin_obj_t * self = self_in ;
if ( n_args = = 0 ) {
// get pin
return MP_OBJ_NEW_SMALL_INT ( gpio_get ( self - > id ) ) ;
if ( ! is_cyw43_pin ( self ) ) {
return MP_OBJ_NEW_SMALL_INT ( gpio_get ( self - > id ) ) ;
}
# if MICROPY_HW_PIN_CYW43_COUNT
return MP_OBJ_NEW_SMALL_INT ( get_cyw43_value ( self ) ) ;
# endif
} else {
// set pin
bool value = mp_obj_is_true ( args [ 0 ] ) ;
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
MP_STATIC_ASSERT ( GPIO_IN = = 0 & & GPIO_OUT = = 1 ) ;
gpio_set_dir ( self - > id , 1 - value ) ;
} else {
gpio_put ( self - > id , value ) ;
if ( ! is_cyw43_pin ( self ) ) {
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
MP_STATIC_ASSERT ( GPIO_IN = = 0 & & GPIO_OUT = = 1 ) ;
gpio_set_dir ( self - > id , 1 - value ) ;
} else {
gpio_put ( self - > id , value ) ;
}
return mp_const_none ;
}
return mp_const_none ;
# if MICROPY_HW_PIN_CYW43_COUNT
update_cyw43_value ( self , value ) ;
# endif
}
return mp_const_none ;
}
// pin.init(mode, pull)
STATIC mp_obj_t machine_pin_obj_init ( size_t n_args , const mp_obj_t * args , mp_map_t * kw_args ) {
return machine_pin_obj_init_helper ( args [ 0 ] , n_args - 1 , args + 1 , kw_args ) ;
if ( ! is_cyw43_pin ( args [ 0 ] ) ) {
return machine_pin_obj_init_helper ( args [ 0 ] , n_args - 1 , args + 1 , kw_args ) ;
}
# if MICROPY_HW_PIN_CYW43_COUNT
return machine_pin_cyw43_obj_init_helper ( args [ 0 ] , n_args - 1 , args + 1 , kw_args ) ;
# endif
}
MP_DEFINE_CONST_FUN_OBJ_KW ( machine_pin_init_obj , 1 , machine_pin_obj_init ) ;
@ -276,40 +463,59 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_
// pin.low()
STATIC mp_obj_t machine_pin_low ( mp_obj_t self_in ) {
machine_pin_obj_t * self = MP_OBJ_TO_PTR ( self_in ) ;
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
gpio_set_dir ( self - > id , GPIO_OUT ) ;
} else {
gpio_clr_mask ( 1u < < self - > id ) ;
if ( ! is_cyw43_pin ( self ) ) {
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
gpio_set_dir ( self - > id , GPIO_OUT ) ;
} else {
gpio_clr_mask ( 1u < < self - > id ) ;
}
return mp_const_none ;
}
# if MICROPY_HW_PIN_CYW43_COUNT
update_cyw43_value ( self , 0 ) ;
return mp_const_none ;
# endif
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1 ( machine_pin_low_obj , machine_pin_low ) ;
// pin.high()
STATIC mp_obj_t machine_pin_high ( mp_obj_t self_in ) {
machine_pin_obj_t * self = MP_OBJ_TO_PTR ( self_in ) ;
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
gpio_set_dir ( self - > id , GPIO_IN ) ;
} else {
gpio_set_mask ( 1u < < self - > id ) ;
if ( ! is_cyw43_pin ( self ) ) {
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
gpio_set_dir ( self - > id , GPIO_IN ) ;
} else {
gpio_set_mask ( 1u < < self - > id ) ;
}
return mp_const_none ;
}
# if MICROPY_HW_PIN_CYW43_COUNT
update_cyw43_value ( self , 1 ) ;
return mp_const_none ;
# endif
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1 ( machine_pin_high_obj , machine_pin_high ) ;
// pin.toggle()
STATIC mp_obj_t machine_pin_toggle ( mp_obj_t self_in ) {
machine_pin_obj_t * self = MP_OBJ_TO_PTR ( self_in ) ;
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
if ( GPIO_IS_OUT ( self - > id ) ) {
gpio_set_dir ( self - > id , GPIO_IN ) ;
if ( ! is_cyw43_pin ( self ) ) {
if ( GPIO_IS_OPEN_DRAIN ( self - > id ) ) {
if ( GPIO_IS_OUT ( self - > id ) ) {
gpio_set_dir ( self - > id , GPIO_IN ) ;
} else {
gpio_set_dir ( self - > id , GPIO_OUT ) ;
}
} else {
gpio_set_dir ( self - > id , GPIO_OUT ) ;
gpio_xor_mask ( 1u < < self - > id ) ;
}
} else {
gpio_xor_mask ( 1u < < self - > id ) ;
return mp_const_none ;
}
# if MICROPY_HW_PIN_CYW43_COUNT
update_cyw43_value ( self , self - > last_output_value ^ 1 ) ;
return mp_const_none ;
# endif
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1 ( machine_pin_toggle_obj , machine_pin_toggle ) ;
@ -357,6 +563,10 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_
{ MP_QSTR_hard , MP_ARG_BOOL , { . u_bool = false } } ,
} ;
machine_pin_obj_t * self = MP_OBJ_TO_PTR ( pos_args [ 0 ] ) ;
if ( is_cyw43_pin ( self ) ) {
mp_raise_ValueError ( MP_ERROR_TEXT ( " expecting a regular GPIO Pin " ) ) ;
}
mp_arg_val_t args [ MP_ARRAY_SIZE ( allowed_args ) ] ;
mp_arg_parse_all ( n_args - 1 , pos_args + 1 , kw_args , MP_ARRAY_SIZE ( allowed_args ) , allowed_args , args ) ;
@ -400,16 +610,31 @@ STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, i
( void ) errcode ;
machine_pin_obj_t * self = self_in ;
if ( ! is_cyw43_pin ( self ) ) {
switch ( request ) {
case MP_PIN_READ : {
return gpio_get ( self - > id ) ;
}
case MP_PIN_WRITE : {
gpio_put ( self - > id , arg ) ;
return 0 ;
}
}
return - 1 ;
}
# if MICROPY_HW_PIN_CYW43_COUNT
switch ( request ) {
case MP_PIN_READ : {
return gpio_get ( self - > id ) ;
return get_cyw43_value ( self ) ;
}
case MP_PIN_WRITE : {
gpio_put ( self - > id , arg ) ;
update_cyw43_value ( self , arg ) ;
return 0 ;
}
}
return - 1 ;
# endif
}
STATIC const mp_pin_p_t pin_pin_p = {
@ -457,5 +682,8 @@ mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t obj) {
mp_raise_ValueError ( MP_ERROR_TEXT ( " expecting a Pin " ) ) ;
}
machine_pin_obj_t * pin = MP_OBJ_TO_PTR ( obj ) ;
if ( is_cyw43_pin ( pin ) ) {
mp_raise_ValueError ( MP_ERROR_TEXT ( " expecting a regular GPIO Pin " ) ) ;
}
return pin - > id ;
}