Note that the cheap ($5 USD) Pro Micro microcontrollers sold on eBay, based on ATmega32u4 microcontroller, can be programmed using free open source tools, either in the Arduino environment (as Arduino Leonardo – these have the Arduino Leonardo bootloader (and not Arduino Pro Micro or Atmel DFU), but with a Sparkfun Pro Micro pinout), PlatformIO, or on bare metal using avr-gcc and avr-libc. These have a native USB controller implemented inside the microcontroller, so they can become any USB 2.0 LS (low speed, 1 Mbit/s) or FS (full speed, 12 Mbit/s) device. There is no FTDI chip, no serial-to-USB bridge, and no particular drivers needed. These are often used to implement HID devices – keyboards, mice, joystics – and MIDI devices. (The single microcontroller can provide more than one endpoint, for example both an USB Serial and USB Keyboard device.)
To program these, all you need is the Pro Micro clone and an USB cable (USB to micro-USB). Power is provided by the computer (or USB cable), and both normal communications as well as programming (flashing) is done via the USB cable. (Of course, you also need a development environment for your computer, but those are freely downloadable from the internet.)
If you add an ADuM4160/ADuM3160 USB isolator (clone) between the Pro Micro and your computer, you can protect your computer from many mistakes, like accidentally grounding the microcontroller to the wrong ground potential or short-circuiting the USB VCC and GND. These cost around USD $10, but as they are basic implementations of the ADuM4160/ADuM3160 datasheet schematic, they seem to be pretty acceptable implementations for this kind of stuff. (Note that many of them have a small DIP switch to choose between low-speed/LS (1 Mbit/s) and full-speed/FS (12 Mbit/s), you generally want it to be in the full speed position.)
The USB Serial device looks like a standard COM port to Windows (and a standard serial device in other operating systems), but baud rate, bits per byte, and the number of stop bits are all irrelevant; not used. Even a simple Arduino sketch can transfer about 1,000,000 bytes per second continuously from the machine to the microcontroller, or vice versa. (Ping-pong is a bit more complicated, as although USB is full duplex, the details on how the software on both the computer and on the microcontroller handles the transfers dictates how much of the theoretical bandwidth you can achieve; and usually depends on whether you can keep data flowing, or have to do a query-response type thing.)
The USB Human Interface Device (HID) protocol does not need any special drivers, but the data rate is capped at 64,000 bytes per second (somewhat less in practice, as you can send one packet of up to 64 bytes every millisecond).
The pinout on these Pro Micro clones is
(micro-USB) (TXO) PD3 TX RAW (RAW) (RXI) PD2 RX GND (GND) (GND) GND RST (RST) (GND) GND VCC (VCC) (2) PD1 SDA PF4 (A3) (3) PD0 SCL PF5 (A2) (4) PD4 PF6 (A1) (5) PC6 PF7 (A0) (6) PD7 SCK PB1 (15) (7) PE6 MISO PB3 (14) (8) PB4 MOSI PB2 (16) (9) PB5 PB6 (10)where the pin label on the board is in parentheses, and
Pxn means GPIO bank
x bit/pin
n.
An Arduino sketch that puts each byte written to the USB Serial port to pins (3), (2), (RXI), (TXO), (A3), (A2), (A1), and (A0), listed from least significant bit to most significant bit, would be rather trivial. This also reserves (4) and (6) (although you could use them as inputs), so it uses both UART and I2C pins, but leaves the three SPI pins and five other pins unused, for you to perhaps use for some other purpose.
// SPDX-License-Identifier: CC0-1.0
// Choose "Tools" > "Board" > "Arduino AVR Boards" > "Arduino Leonardo"
static uint8_t mask;
void setup() {
Serial.begin(9600); // Does not matter for ATmega32u4
pinMode(3, OUTPUT); // PD0 (3) Data bit 0
pinMode(2, OUTPUT); // PD1 (2) Data bit 1
pinMode(0, OUTPUT); // PD2 (RXI) Data bit 2
pinMode(1, OUTPUT); // PD3 (TXO) Data bit 3
pinMode(21, OUTPUT); // PF4 (A3) Data bit 4
pinMode(20, OUTPUT); // PF5 (A2) Data bit 5
pinMode(19, OUTPUT); // PF6 (A1) Data bit 6
pinMode(18, OUTPUT); // PF7 (A0) Data bit 7
pinMode(4, OUTPUT); // PD4 (4) Mask bit 4
pinMode(6, OUTPUT); // PD7 (6) Mask bit 6
mask = 0;
}
void loop() {
// Loop whenever we receive data via the USB Serial port
while (Serial && Serial.available() > 0) {
uint8_t data = Serial.read();
uint8_t d = (data & 15) | mask;
uint8_t f = (data & 240);
// Update the GPIO banks with as little delay between the two as possible.
PORTD = d;
PORTF = f;
}
}
The two "mask" pins, (4) and (6), are also in the D bank, and we update the states of all D and F bank pins at once, so that's why they're included above even though we don't use them for anything. If they are used as inputs, then mask value determines whether the internal pull-up resistors are enabled for them or not.
ATmega32u4 has 2560 bytes of RAM, and in the Arduino environment, the above sketch uses only 150 bytes (leaving 2410 bytes of RAM unused). The sketch uses 3818 bytes, or 13%, of the available Flash (read-only/code memory). So, there is definitely room to extend the program. The 5V Pro Micro clones run at 16 MHz, and the 3.3V ones at 8 MHz; I prefer the 5V ones. (The 5V ones use 0 to 5V logic states on the pins, and the 3.3V ones 0 to 3.3V.)
There are other, perhaps better and cheaper microcontrollers out there, but I believe the old ATmega32u4 is a good introductory device, being a simple 8-bit AVR architecture, but with a native USB interface.