@@ -74,6 +74,65 @@ STATIC void claim_and_never_reset_pins(mp_obj_t seq) {
7474 }
7575}
7676
77+ STATIC void preflight_pins_or_throw (uint8_t clock_pin , uint8_t * rgb_pins , uint8_t rgb_pin_count , bool allow_inefficient ) {
78+ uint32_t port = clock_pin / 32 ;
79+ uint32_t bit_mask = 1 << (clock_pin % 32 );
80+
81+ for (uint8_t i = 0 ; i < rgb_pin_count ; i ++ ) {
82+ uint32_t pin_port = rgb_pins [i ] / 32 ;
83+
84+ if (pin_port != port ) {
85+ mp_raise_ValueError_varg (
86+ translate ("rgb_pins[%d] is not on the same port as clock" ), i );
87+ }
88+
89+ uint32_t pin_mask = 1 << (rgb_pins [i ] % 32 );
90+ if (pin_mask & bit_mask ) {
91+ mp_raise_ValueError_varg (
92+ translate ("rgb_pins[%d] duplicates another pin assignment" ), i );
93+ }
94+
95+ bit_mask |= pin_mask ;
96+ }
97+
98+ if (allow_inefficient ) {
99+ return ;
100+ }
101+
102+ uint8_t byte_mask = 0 ;
103+ if (bit_mask & 0x000000FF ) byte_mask |= 0b0001 ;
104+ if (bit_mask & 0x0000FF00 ) byte_mask |= 0b0010 ;
105+ if (bit_mask & 0x00FF0000 ) byte_mask |= 0b0100 ;
106+ if (bit_mask & 0xFF000000 ) byte_mask |= 0b1000 ;
107+
108+ uint8_t bytes_per_element = 0xff ;
109+ uint8_t ideal_bytes_per_element = (rgb_pin_count + 7 ) / 8 ;
110+
111+ switch (byte_mask ) {
112+ case 0b0001 :
113+ case 0b0010 :
114+ case 0b0100 :
115+ case 0b1000 :
116+ bytes_per_element = 1 ;
117+ break ;
118+
119+ case 0b0011 :
120+ case 0b1100 :
121+ bytes_per_element = 2 ;
122+ break ;
123+
124+ default :
125+ bytes_per_element = 4 ;
126+ break ;
127+ }
128+
129+ if (bytes_per_element != ideal_bytes_per_element ) {
130+ mp_raise_ValueError_varg (
131+ translate ("Pinout uses %d bytes per element, which consumes more than the ideal %d bytes. If this cannot be avoided, pass allow_inefficient=True to the constructor" ),
132+ bytes_per_element , ideal_bytes_per_element );
133+ }
134+ }
135+
77136//| :class:`~_protomatter.Protomatter` displays an in-memory framebuffer to an LED matrix.
78137//|
79138//| .. class:: Protomatter(width, bit_depth, rgb_pins, addr_pins, clock_pin, latch_pin, oe_pin, *, doublebuffer=True, framebuffer=None)
@@ -141,6 +200,8 @@ STATIC mp_obj_t protomatter_protomatter_make_new(const mp_obj_type_t *type, size
141200 validate_pins (MP_QSTR_rgb_pins , rgb_pins , MP_ARRAY_SIZE (self -> rgb_pins ), args [ARG_rgb_list ].u_obj , & rgb_count );
142201 validate_pins (MP_QSTR_addr_pins , addr_pins , MP_ARRAY_SIZE (self -> addr_pins ), args [ARG_addr_list ].u_obj , & addr_count );
143202
203+ preflight_pins_or_throw (clock_pin , rgb_pins , rgb_count , true);
204+
144205 mp_obj_t framebuffer = args [ARG_framebuffer ].u_obj ;
145206 if (framebuffer == mp_const_none ) {
146207 int width = args [ARG_width ].u_int ;
0 commit comments