{"id":19203366,"url":"https://github.com/rouming/ft232h-bluepill","last_synced_at":"2025-10-30T01:02:19.909Z","repository":{"id":230075247,"uuid":"778408462","full_name":"rouming/FT232H-bluepill","owner":"rouming","description":"FT232H implementation on the SPI32F103 BluePill board","archived":false,"fork":false,"pushed_at":"2024-03-31T21:13:36.000Z","size":3053,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-04T14:14:42.543Z","etag":null,"topics":["bluepill","ftdi","mpsse","stm32","stm32f103"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rouming.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-27T17:03:03.000Z","updated_at":"2024-05-28T07:37:35.000Z","dependencies_parsed_at":"2024-03-31T22:23:48.006Z","dependency_job_id":null,"html_url":"https://github.com/rouming/FT232H-bluepill","commit_stats":null,"previous_names":["rouming/ft232h-bluepill"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rouming%2FFT232H-bluepill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rouming%2FFT232H-bluepill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rouming%2FFT232H-bluepill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rouming%2FFT232H-bluepill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rouming","download_url":"https://codeload.github.com/rouming/FT232H-bluepill/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240275924,"owners_count":19775616,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bluepill","ftdi","mpsse","stm32","stm32f103"],"created_at":"2024-11-09T12:48:02.125Z","updated_at":"2025-10-30T01:02:19.903Z","avatar_url":"https://github.com/rouming.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FT232H on SPI32F103 BluePill board\n\nThis firmware is for the SPI32F103 BluePill board, acting like the FT232H\ndevice. Not every feature is there, but it covers some crucial MPSSE commands\nI really needed. At least on the USB level, the firmware mimics the FT232H,\nand both the kernel ftdi_sio driver and userspace libftdi implementation\ndon't spot any differences.\n\nWhy? There are a couple of reasons driving me. The biggest one is the busted\nSPI modes 1 and 3. It's a real pain when you spend hours trying to get something\nto work, only to find out it's not supported ([here](https://forums.adafruit.com/viewtopic.php?t=124869), [here](https://electronics.stackexchange.com/questions/360086/make-ftdi-2232d-do-spi-mode-1-properly-data-seems-1-2-clock-cycle-off), [here](https://www.ftdicommunity.com/index.php?topic=692.0)).\nThe only place I found a mention of this was in [Application Note AN_114](https://ftdichip.com/Support/Documents/AppNotes/AN_114_FTDI_Hi_Speed_USB_To_SPI_Example.pdf), where\nit casually drops: \"FTDI device can only support mode 0 and mode 2 due to the\nlimitation of MPSSE engine.\" Yeah, limitations, sure thing.\n\nWhen tinkering with the original FT232H, I stumbled upon another issue. It led\nto a messy workaround of clearing the TX buffer on the device side before\nsending an MPSSE write request that generates a read response (like an SPI\nread triggered by the MPSSE_DO_READ (0x20) bit). Turns out, the FTDI chip\nsends 2-byte modem status in each USB \"IN\" packet once latency timeout (16 ms)\nexpires. The behavior well described [here](https://www.ftdichip.com/Documents/AppNotes/AN232B-04_DataLatencyFlow.pdf). This leads to a lot of confusion and people complain about\nthe \"FT_Read() returns 0 bytes\" problem. The workaround involves calling\n`ftdi_usb_purge_tx_buffer()` or `tciflush()` just before the write request,\nor reading data unless zero length is received. Anyway, with plenty of library\nimplementations out there (C, Python, Go, etc.), why not\nimplement the necessary stuff in the STM32 firmware and run it smoothly on\nthe BluePill without these headaches? (Yeah, for now I decided to make read\nblocking to avoid an flushing, since UART is not supported, but that should\nbe easy to fix in the future).\n\n### How to use\n\nBuild and flash BluePill board. For example for the open-source ST-Link\ntools (e.g. stlink-tools package on Debian):\n\n```\nSERIAL=$(st-info --probe | grep serial | awk '{print $2}')\nmake SERIAL=$SERIAL flash-stlink\n```\n\nOnce freshly flashed BluePill is connected to the host via USB, host\nshould detect the FT232H device. Done.\n\n### Pin mappings\n\nFirmware does the following mapping of the FT232H pins to STM32 pins:\n\nADBUS\n```\nFT232H    STM32\n   AD0 -\u003e PA5\n   AD1 -\u003e PA7\n   AD2 -\u003e PA6\n   AD3 -\u003e PA4\n   AD4 -\u003e PA3\n   AD5 -\u003e PA2\n   AD6 -\u003e PA1\n   AD7 -\u003e PA0\n```\n\nACBUS\n```\nFT232H    STM32\n   AC0 -\u003e PB12\n   AC1 -\u003e PB13\n   AC2 -\u003e PB14\n   AC3 -\u003e PB15\n   AC4 -\u003e PA8\n   AC5 -\u003e PA9\n   AC6 -\u003e PA10\n   AC7 -\u003e PA11\n```\n\n### Supported commands\n\nFirst of all see the list of supported commands in the real FT232H device\nin the corresponding [spec](https://ftdichip.com/wp-content/uploads/2020/08/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf).\n\n#### USB control requests:\n\nThe following requests implemented as NOP stubs to shutup ftdi_sio kernel driver:\n\n- **FTDI_SET_LATENCY_TIMER** - !!! TODO !!!, does nothing, returns success\n- **FTDI_READ_EEPROM** - !!! TODO !!!, always returns 0xffff in IN bulk response\n- **FTDI_SET_BITMODE** - !!! TODO !!!, currently only MPSSE mode is supported\n- **FTDI_SET_BAUD_RATE** - !!! TODO !!!, does nothing, returns success\n- **FTDI_SET_FLOW_CTRL** - !!! TODO !!!, does nothing, returns success\n\nImplemented:\n\n- **FTDI_RESET** - resets device to initial state\n\n#### USB bulk OUT requests:\n\n- **TCK_DIVISOR** - sets clock frequency, currenly only used for the CLK_BYTES command\n- **SET_BITS_LOW** - configures 8 GPIO pins of the ADBUS\n- **SET_BITS_HIGH** - configures 8 GPIO pins of the ACBUS\n- **MPSSE_DO_WRITE** - clocks data bytes out. All modifiers flags are supported\n- **MPSSE_DO_READ** - clocks data bytes in. All modifiers flags are supported\n- **CLK_BYTES** - clocks n x 8 bits with no data transfer\n\n### Examples\n\nIn the [examples/](./examples) folder a few Python examples can be found.\n\n###### [examples/mpsse_spi.py](./examples/mpsse_spi.py)\n\nTest \"clocks data bytes in or out\" or initiates SPI write-read request.\nBefore running the test, please don't forget to connect PA7 and PA6 pins\ntogether to have a loopback receive.\n\nThe test does the following:\n\n1. Sets bitmode to the MPSSE (the only mode supported by this firmware).\n2. Sets SPI clock frequency to the 1Mhz (for the SPI 1.125Mhz is hardcoded)\n3. Configures 3 GPIO pins of the ADBUS to output direction: SK (clock),\n   CS (chip select), DO (device out). Set CS pin to high.\n   On the STM32 these pins are mapped as the following:\n\n```\n     SK (AD0) -\u003e PA5\n     DO (AD1) -\u003e PA7\n     DI (AD2) -\u003e PA6\n     CS (AD3) -\u003e PA4\n```\n\n4. Calls the `ftdi_usb_purge_tx_buffer()`, which is meaningfull only on the\n   real FT232H device, for this firmware this call has no effect, since all\n   the read calls are blocking.\n\n5. Writes several requests in one bulk packet:\n\n  - configures CS to low\n  - initiates SPI write-read\n  - configures CS to high\n\n6. Reads SPI reply back. If device is configured for the loopback receive, i.e.\n   PA7 and PA6 pins are connected together, then 0x81 byte should be read back.\n\nThe resulting osciloscope screenshot:\n\n![](./images/correct_stm32_spi/initial-clock-NEG--write-on-POS--mode-1.png)\n\n###### [examples/mpsse_clk_bytes.py](./examples/mpsse_clk_bytes.py)\n\nTest \"clocks n x 8 bits with no data transfer\", or simply generates pulse\ntrain on the SK (AD0) pin.\n\nThe test does the following:\n\n1. Sets bitmode to the MPSSE (the only mode supported by this firmware).\n2. Sets clock frequency to the 1Mhz\n3. Configures 3 GPIO pins of the ADBUS to output direction: SK (clock),\n   CS (chip select), DO (device out). Set CS pin to high.\n   Mappings see in the previous example.\n\n4. Writes several requests in one bulk packet:\n\n  - configures CS to low\n  - initiates 8 pulse train\n  - configures CS to high\n\nThe resulting osciloscope screenshot:\n\n![](./images/pulse-train.png)\n\n### Specs\n\n[Application Note AN_108](https://ftdichip.com/wp-content/uploads/2020/08/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frouming%2Fft232h-bluepill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frouming%2Fft232h-bluepill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frouming%2Fft232h-bluepill/lists"}