WeAct STM32F411CEU6 black pill
Re: WeAct STM32F411CEU6 black pill
With the PyBoard I was used to specify SPI parameters by name like SPI("Y", "Y5",..) for the second SPI module. With the black pill these names are not accepted. I succeeded with SPI(2,"PB12",..), but I wonder if it is possible to use a symbolic name for the SPI (and other) busses. If so where can I find these names?
Rob.
Rob.
Re: WeAct STM32F411CEU6 black pill
The pinout image is here:
https://github.com/WeActTC/MiniF4-STM32 ... Balint.png
https://github.com/WeActTC/MiniF4-STM32 ... Balint.png
Re: WeAct STM32F411CEU6 black pill
The "X" and "Y" names come from the boards mpconfigboard.h file.
For the pyboard, it's here:
https://github.com/micropython/micropyt ... oard.h#L56
The WeAct board config file doesn't provide any names and I'm not sure what you'd call them anyways since there isn't anything obvious on the board to use other than the SPI port number (i.e. 1, 2, or 3).
For the pyboard, it's here:
https://github.com/micropython/micropyt ... oard.h#L56
The WeAct board config file doesn't provide any names and I'm not sure what you'd call them anyways since there isn't anything obvious on the board to use other than the SPI port number (i.e. 1, 2, or 3).
Re: WeAct STM32F411CEU6 black pill
Agreed, the logic for symbolic names of the 2 SPI interfaces for the original PyBoard (X or Y side) doesn't work for the black pill. The first 2 could be called 'A' and 'B', but the remaining have also 'A' and/or 'B' pins. So it will be 1,2,..etc
[addition]
A related 'issue': I see different pins with the same symbolic names. For example Pin B6 and B8 have both SCL1. When printing the I2C(1) object I see that B6 is used. Explicit selection of B8 is refused. When (for example) using B6/B7 as serial port, how can I use B8/B9 for I2C(1)?
Rob.
[addition]
A related 'issue': I see different pins with the same symbolic names. For example Pin B6 and B8 have both SCL1. When printing the I2C(1) object I see that B6 is used. Explicit selection of B8 is refused. When (for example) using B6/B7 as serial port, how can I use B8/B9 for I2C(1)?
Rob.
Re: WeAct STM32F411CEU6 black pill
I think the answer is "use alternate pin function", something like for SCL1:
p = Pin("B8", mode=Pin.AF_PP, af = Pin.AF4_I2C1)
Re: WeAct STM32F411CEU6 black pill
One option is to create a custom board type and modify the mpconfigboard.h file:
https://github.com/mcauser/WEACT_F411CE ... .h#L39-L44
Another option is to open I2C1 and then modify the pin mux afterwards.
Here's some example code that does this: Running this produced this output for me: Note that there is a bug in the current version of Micropython which I submitted a PR for: https://github.com/micropython/micropython/pull/6329
This causes the prints for B6 and B7 to look like this instead: the dump I did was from a patched version of micropython.
https://github.com/mcauser/WEACT_F411CE ... .h#L39-L44
Another option is to open I2C1 and then modify the pin mux afterwards.
Here's some example code that does this:
Code: Select all
# Example which runs on the WeACT STM32F411CEU6 board.
#
# By default I2C(1) uses B6/B7
#
# This example shows how to move this to pins B8/B9
import machine
from machine import Pin
b6 = Pin('B6')
b7 = Pin('B7')
b8 = Pin('B8')
b9 = Pin('B9')
def dump(label):
print('-----', label)
print(' ', b6)
print(' ', b7)
print(' ', b8)
print(' ', b9)
print('')
dump('Before opening I2C')
i2c = machine.I2C(1) # uses B6/B7
dump('After opening I2C')
# Switch B6/B7 back to being GPIO
b6.init(Pin.IN)
b7.init(Pin.IN)
dump('After making B6/B7 GPIO')
b8.init(Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, alt=Pin.AF4_I2C1)
b9.init(Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, alt=Pin.AF4_I2C1)
dump('After enabling I2C(1) on B8/B9')
Code: Select all
>>> import weact_i2c
----- Before opening I2C
Pin(Pin.cpu.B6, mode=Pin.IN)
Pin(Pin.cpu.B7, mode=Pin.IN)
Pin(Pin.cpu.B8, mode=Pin.IN)
Pin(Pin.cpu.B9, mode=Pin.IN)
----- After opening I2C
Pin(Pin.cpu.B6, mode=Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B7, mode=Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B8, mode=Pin.IN)
Pin(Pin.cpu.B9, mode=Pin.IN)
----- After making B6/B7 GPIO
Pin(Pin.cpu.B6, mode=Pin.IN)
Pin(Pin.cpu.B7, mode=Pin.IN)
Pin(Pin.cpu.B8, mode=Pin.IN)
Pin(Pin.cpu.B9, mode=Pin.IN)
----- After enabling I2C(1) on B8/B9
Pin(Pin.cpu.B6, mode=Pin.IN)
Pin(Pin.cpu.B7, mode=Pin.IN)
Pin(Pin.cpu.B8, mode=Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B9, mode=Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, af=Pin.AF4_I2C1)
This causes the prints for B6 and B7 to look like this instead:
Code: Select all
----- After making B6/B7 GPIO
Pin(Pin.cpu.B6, mode=Pin.ALT_OPEN_DRAIN, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B7, mode=Pin.ALT_OPEN_DRAIN, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B8, mode=Pin.IN)
Pin(Pin.cpu.B9, mode=Pin.IN)
----- After enabling I2C(1) on B8/B9
Pin(Pin.cpu.B6, mode=Pin.ALT_OPEN_DRAIN, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B7, mode=Pin.ALT_OPEN_DRAIN, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B8, mode=Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B9, mode=Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, af=Pin.AF4_I2C1)
Re: WeAct STM32F411CEU6 black pill
Hello Dave,
Great service to explain and demonstrate the alternate pin functionality! Saves me a lot of time. I'm sure I would have struggled with the sequence, certainly with the MicroPython issue.
Rob.
Great service to explain and demonstrate the alternate pin functionality! Saves me a lot of time. I'm sure I would have struggled with the sequence, certainly with the MicroPython issue.
Rob.
Re: WeAct STM32F411CEU6 black pill
Hello Dave,
When I run your example under 1.12 665 it seems your issue is fixed, but there may be a problem still.
The last line in your example says: 'dump('After enabling I2C1 on B8/B9'), but the I2C object is not yet initialized.
After a i2c.init(pyb.I2C.MASTER) the dump shows:
And I'm not sure if I2C is really on ports B8/B9 (I have not yet done a hardware test).
Note: I imported I2C from 'pyb', because the I2C.init() from 'machine' asks for scl/sda, and I want to see if the alternate 'default' Pins are used.
When I run your example under 1.12 665 it seems your issue is fixed, but there may be a problem still.
The last line in your example says: 'dump('After enabling I2C1 on B8/B9'), but the I2C object is not yet initialized.
After a i2c.init(pyb.I2C.MASTER) the dump shows:
Code: Select all
---- After init I2C1
Pin(Pin.cpu.B6, mode=Pin.ALT_OPEN_DRAIN, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B7, mode=Pin.ALT_OPEN_DRAIN, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B8, mode=Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, af=Pin.AF4_I2C1)
Pin(Pin.cpu.B9, mode=Pin.ALT_OPEN_DRAIN, pull=Pin.PULL_UP, af=Pin.AF4_I2C1)
Note: I imported I2C from 'pyb', because the I2C.init() from 'machine' asks for scl/sda, and I want to see if the alternate 'default' Pins are used.
Re: WeAct STM32F411CEU6 black pill
It looks to me like I2C1 should be on pins B8/B9 (based on your dump), and B6/B7 are configured back as GPIOs (the pull parameter being dropped is the clue here).
Just FYI: when you use machine.I2C and an id of -1, then it will do software I2C which uses the pins in GPIO mode and this mode can use any pins, whereas the B8/B9 thing is for using the pins with HW I2C, which can only go on pins that the HW supports.
The big thing is that when using HW mode, you generally only want the SCL/SDA pins to be present on one set of pins (which is why you should configure B6/B7 back to being GPIO).
Just FYI: when you use machine.I2C and an id of -1, then it will do software I2C which uses the pins in GPIO mode and this mode can use any pins, whereas the B8/B9 thing is for using the pins with HW I2C, which can only go on pins that the HW supports.
The big thing is that when using HW mode, you generally only want the SCL/SDA pins to be present on one set of pins (which is why you should configure B6/B7 back to being GPIO).
Re: WeAct STM32F411CEU6 black pill
Hello Dave,
the proof of the pudding...
I connected a small I2C OLED display with scl/sda on B8/B9 and extended the code with an i2c.scan().
This showed the correct I2C address of the display. After wiring the display to B6/B7 i2c.scan() shows an empty list, OK!
And print(i2c) shows:
So the alternate pin facility works! This was with pyb.I2C.
It also works with machine.I2C. In that case I left out the i2c.init() to avoid having to specify scl/sda pins. The docs of machine.I2C do not tell me if the i2c object is initialised or not during creation (unlike the docs of pyb.I2C), but I assume yes.
Even without this i2c.init() the correct I2C address is shown with the i2c.scan() with the scl/sda lines of the display on pins B8/B9. One peculiarity: a print(i2c) shows:
Still the old pins, even though the display is really wired to B8/B9 and responding to its I2C address!
Then I tried a little test program for the OLED display using the SH1106 library of
Radomir Dopieralski (@deshipu), Robert Hammelrath (@robert-hh).
Originally this library insisted on specifying pins for scl/sda. After opening an issue with a request to be able to simply specify I2C(1) I received a fix. Then I used the alternate function facility conform your suggestions and now B8/B9 are working fine as default scl/sda pins with I2C(1)!
the proof of the pudding...
I connected a small I2C OLED display with scl/sda on B8/B9 and extended the code with an i2c.scan().
This showed the correct I2C address of the display. After wiring the display to B6/B7 i2c.scan() shows an empty list, OK!
And print(i2c) shows:
Code: Select all
I2C(1, I2C.MASTER, baudrate=480000)
It also works with machine.I2C. In that case I left out the i2c.init() to avoid having to specify scl/sda pins. The docs of machine.I2C do not tell me if the i2c object is initialised or not during creation (unlike the docs of pyb.I2C), but I assume yes.
Even without this i2c.init() the correct I2C address is shown with the i2c.scan() with the scl/sda lines of the display on pins B8/B9. One peculiarity: a print(i2c) shows:
Code: Select all
I2C(1, scl=B6, sda=B7, freq=480000)
Then I tried a little test program for the OLED display using the SH1106 library of
Radomir Dopieralski (@deshipu), Robert Hammelrath (@robert-hh).
Originally this library insisted on specifying pins for scl/sda. After opening an issue with a request to be able to simply specify I2C(1) I received a fix. Then I used the alternate function facility conform your suggestions and now B8/B9 are working fine as default scl/sda pins with I2C(1)!