I seem to have fritzed one or two of the pins on my STM32F429I-DISC0 board (now replaced by an updated version, STM32F429I-DISC1; that last character was a 0!); after some hair-pulling it turns out that one of said pins is used by the only externally-accessible I2C peripheral on the board; so, until the replacement arrives, here are some interesting facts about the PCF8547A.
Use for output (to an LED)
It turns out that the chip is unlike most of the digital I/O devices you'll find, in that the pins act as current sinks rather than current sources (page down to the hand-drawn circuit diagram). Normally (as for example with the STM32F4), you'd connect a resistor to the pin, the anode of an LED to the resistor, and the cathode of the LED to ground. With the PCF8547A, you connect the anode of the LED to VCC, the cathode of the LED to the resistor, and the other end of the resistor to the pin.
This means that you write a 0 to the pin to turn the LED on.
Use for input (from a switch)
Normally you'd have a pull-up resistor (possibly supplied by the MCU internally), so that when the switch is open the MCU sees 1, when it's closed the MCU sees 0.
For the PCF8547A, where the pins are bidirectional, you configure the pin to provide a pull-up by writing 1 to it from the MCU.
Arduino
As I said above, my STM32F4 board isn't working; so I explored the chip using an Arduino Due (and the Arduino IDE, so the code is C++ even though in a .ino file).
The Due has two I2C channels; the easily-visible pins at the top of the board are labelled SDA1, SCL1 and it took me a while to realise that the first channel uses the pins labelled SDA, SCL hiding away at the bottom right. (To use the second channel, address it as Wire1
, e.g.Wire1.begin()
).
The Arduino code:
#include <Arduino.h> #include <Wire.h> const unsigned char chip_address = 0x70 / 2; void setup() { Wire.begin(); } void loop() { unsigned char input; unsigned char output; Wire.requestFrom(chip_address, 1); input = Wire.read(); // The pushbuttons are on pins 4 .. 7, the LEDs on pins 0 .. 3. // If PB4 is 1, write 0 to PB0 // Always write 1 to the pushbuttons output = ~(input >> 4); Wire.beginTransmission(chip_address); Wire.write(output); int status = Wire.endTransmission(); delay(1000); }
STM32F4 equivalent
For interest, the draft initialization code for the STM32F4 - the equivalent of the Arduino'sWrite.begin()
- is, using AdaCore's bareboard package,
STM32F4.RCC.GPIOA_Clock_Enable; STM32F4.GPIO.Configure_Alternate_Function (STM32F42xxx.GPIO_A, Pin => STM32F4.GPIO.Pin_8, AF => STM32F4.GPIO.GPIO_AF_I2C3); STM32F4.GPIO.Configure_IO (STM32F42xxx.GPIO_A, Pin => STM32F4.GPIO.Pin_8, Config => (Mode => STM32F4.GPIO.Mode_AF, Output_Type => STM32F4.GPIO.Open_Drain, Speed => STM32F4.GPIO.Speed_25MHz, Resistors => STM32F4.GPIO.Floating)); STM32F4.RCC.GPIOC_Clock_Enable; STM32F4.GPIO.Configure_Alternate_Function (STM32F42xxx.GPIO_C, Pin => STM32F4.GPIO.Pin_9, AF => STM32F4.GPIO.GPIO_AF_I2C3); STM32F4.GPIO.Configure_IO (STM32F42xxx.GPIO_C, Pin => STM32F4.GPIO.Pin_9, Config => (Mode => STM32F4.GPIO.Mode_AF, Output_Type => STM32F4.GPIO.Open_Drain, Speed => STM32F4.GPIO.Speed_25MHz, Resistors => STM32F4.GPIO.Floating)); STM32F4.RCC.I2C3_Clock_Enable; STM32F4.I2C.Configure (Port => STM32F42xxx.I2C_3, Clock_Speed => 10_000, Mode => STM32F4.I2C.I2C_Mode, Duty_Cycle => STM32F4.I2C.DutyCycle_2, Own_Address => 16#00#, Ack => STM32F4.I2C.Ack_Enable, Ack_Address => STM32F4.I2C.AcknowledgedAddress_7bit);
No comments:
Post a Comment