Skip to content

Bluetooth! ​

It was the last remaining uncertainty: will the bluetooth chip I chose work ? And yes it works !!!!

Wiring detils ​

Top view (shield side up), antenna at the bottom:

              31 30 29 28 27 26 25 24 23 22
            +-------------------------------+
         32 |                               | 21
         33 |                               | 20
         34 |                               | 19
         35 |                               | 18
         36 |                               | 17
         37 |                               | 16
         38 |                               | 15
         39 |                               | 14
         40 |                               | 13
         41 |                               | 12
         42 |                               | 11
         43 |                               | 10
         44 |                               | 9
         45 |                               | 8
         46 |                               | 7
         47 |                               | 6
         48 |                               | 5
         49 |                               | 4
         50 |                               | 3
         51 |                               | 2
         52 |                               | 1
            |                               |
            |            ANTENNA            |
            +-------------------------------+
  • 1.0 mm pitch. Module 13.0 x 26.9 mm.
  • Right edge: pins 1-21, bottom to top. Top edge: 22-31, right to left. Left edge: 32-52, top to bottom.
  • Dead-bug (pads facing up), left and right swap: pin 1 is then on the left, pin 52 on the right.
  • Keep the antenna end clear of metal and wires.

How I wired it to the nucleo ​

Module pinNameConnect toNotes
33VBAT_INNucleo 3V310 µF + 100 nF across pins 32/33, on the module
36VDD_IONucleo 3V3I/O level = 3.3 V
32GNDGND
1, 22, 50, 52GNDGNDat least one more ground, for the radio
34SYS_CTRLPA15drive high > 20 ms after power-up to boot. No internal pull: never leave floating
14BT_RXPB6 (USART1 TX)AT commands, 115200 8N1
13BT_TXPB7 (USART1 RX)
4PCM_CLKVS1053 GPIO6 (SCLK, LQFP pin 11)I2S bit clock
7PCM_SYNCVS1053 GPIO4 (LROUT, LQFP pin 36)I2S word clock
5PCM_INVS1053 GPIO7 (SDATA, LQFP pin 12)I2S data into the module
8RESEToptional: GPIO, open-draininternal pull-up, can stay unconnected
17AIO0/LED0optional: LED + 1 k to 3V3open-drain. Blinks while pairing (reference design)

Power the module before driving UART or I2S, otherwise it gets powered through its I/O pins.

I2S: VS1053 to module ​

VS1053 pin numbers are for its LQFP-48 package (datasheets/vs1053.pdf, pin table). Note the module pins are not in order.

SignalVS1053 pinVS1053 LQFP pinModule pinModule signal
Word clock (48 kHz)GPIO4 / I2S_LROUT367PCM_SYNC
Bit clock (1.536 MHz)GPIO6 / I2S_SCLK114PCM_CLK
DataGPIO7 / I2S_SDATA125PCM_IN

Settings that match: the VS1053 as I2S master at 48 kHz (I2S_CONFIG = 0x4, MCLK off), and the module as slave, 48 kHz, 16-bit I2S: AT+AUXCFG=3 (I2S input) and AT+I2SCFG=3.

Minimal test code ​

cpp
#include <Arduino.h>
#include "sound/VS1053_driver.h"
#include "sound/startup_sound.h" // a short MP3, stored in flash

#define BT_SYS_CTRL PA15
Uart BT(PB7, PB6);                      // USART1: RX <- BT_TX, TX -> BT_RX
VS1053_driver vs(PA10, PA11, PA9, PB3); // XRESET, XCS, XDCS, DREQ
uint32_t pos = 0;

void setup() {
  Serial.begin(115200);

  // SYS_CTRL has no internal pull: high for > 20 ms boots the module.
  digitalWrite(BT_SYS_CTRL, HIGH);
  pinMode(BT_SYS_CTRL, OUTPUT);
  BT.begin(115200); // 8N1, the module's default

  vs.begin(1000000);
  vs.setVolume(40, 40);
  // GPIO4-7 as outputs, I2S_CONFIG = 0x4: master, 48 kHz, 16-bit words.
  vs.setI2SOutput(true);
}

void loop() {
  // Monitor <-> module. The monitor sends "\r\n" on Enter, which is what the
  // AT commands expect.
  while (Serial.available()) BT.write(Serial.read());
  while (BT.available()) Serial.write(BT.read());

  // Loop the clip, 32 bytes each time the VS1053 has room for them.
  if (vs.dreqHigh()) {
    uint32_t n = min((uint32_t)32, STARTUP_SOUND_LEN - pos);
    vs.sendData(STARTUP_SOUND_MP3 + pos, n);
    pos = (pos + n) % STARTUP_SOUND_LEN;
  }
}

The AT commands come from Feasycom's BT1035 programming user guide (the module's datasheet only says "ASCII commands over UART"). Run the monitor with echo on, to see what you type: pio device monitor --echo.

The commands, and what the module answered ​

> is what I typed, the rest is the module's answer as printed in the serial monitor.

1. Is anybody there? ​

> AT
OK
> AT+VER
+VER=FSC-BT1035,V6.1.1,20240521
OK
> AT+NAME
+NAME=FSC-BT1035
OK
> AT+ADDR
+ADDR=00025B00FF05
OK

First try. Power, SYS_CTRL, and TX/RX the right way round.

2. Profiles ​

> AT+PROFILE
+PROFILE=341
OK

341 is a bit field: 0b101010101 = SPP, GATT, HFP-AG (the phone side of a hands-free link), A2DP Source (bit 6) and AVRCP Target. A2DP Source is what makes it a transmitter, and it's on by default. Nothing to change.

3. Scan for receivers ​

Receiver in pairing mode, then:

> AT+SCAN=1
+DEVSTAT=9
OK
+SCAN=1,2,B40F3A9D1537,-55,12,BT5.3-Audio.,240404
+DEVSTAT=1

Each result is index, address type (2 = classic BR/EDR), MAC, RSSI, name length, name, class of device. The guide says a scan ends with +SCAN=E; this firmware ends it with +DEVSTAT=1 (back to idle) instead.

4. Connect ​

> AT+A2DPCONN=B40F3A9D1537
+A2DPSTAT=2
OK
+PAIRED=B40F3A9D1537
+A2DPSTAT=3
+A2DPDEV=B40F3A9D1537,BT5.3-Audio
+A2DPSTAT=5
+A2DPENC=1
+A2DPSTAT=4
+AVRCPSTAT=2
+AVRCPSTAT=3
+HFPSTAT=2
+HFPSTAT=1

The receiver said "connected" out loud. A2DPSTAT goes 2 (connecting), 3 (connected), 5 (paused), 4 (streaming). A2DPENC=1 is the codec: SBC. The HFPSTAT 2 -> 1 at the end is the module trying to open a hands-free (phone call) link, which the receiver declined: no problem for music.

From then on the module reconnects to it by itself at every power-on:

+A2DPSTAT=2
+AVRCPSTAT=2
+AVRCPSTAT=3
...
+A2DPSTAT=3
+A2DPDEV=B40F3A9D1537,BT5.3-Audio
+A2DPSTAT=5
+A2DPENC=1
+A2DPSTAT=4

5. Audio input: I2S ​

Connected and "streaming", but silence: by default the module streams its USB audio input. Switch it to I2S, as a slave (the VS1053 drives the clocks), 48 kHz, 16 bit:

> AT+AUXCFG=3
OK
> AT+I2SCFG=3
OK
> AT+AUXCFG
+AUXCFG=3
OK
> AT+I2SCFG
+I2SCFG=3
OK

Both settings are stored in the module's flash, so this is a one-time setup. I2SCFG is a bit field too: bit 0 enable, bit 1 slave, bit 2 44.1 kHz instead of 48, bit 3 right-justified, bit 4 no 1-bit data delay, bits 5-6 word size. 3 = enabled, slave, 48 kHz, standard I2S, 16 bit. That matches the VS1053: at 48 kHz its bit clock is 12.288 MHz / 8 = 1.536 MHz = 48 kHz x 2 channels x 16 bits.

6. Taddaa! ​

And just like that I had the thing playing my startup_sound mp3 file over bluetooth! Next I (I mean AI) will implement the whole UI for it: run scans, display the signal strength, rename, connect, forget etc. Beautifull!