Functional Description
A Dual-Mode Bluetooth Module geared for audio.
The Violet C Module (hereby referred to as Violet C or Violet, if unspecified) is a Bluetooth SoM supporting Bluetooth BR/EDR + LE, geared for audio over Bluetooth. There are 2 relevant versions of Violet, versions B and C.
Violet B utilizes an older chipset(ATS2853X), whereas Violet C uses a newer chipset(ATS2835X) and supports newer features. The primary difference is that Violet C contains support for LE Audio, as opposed to Violet B, which only support Classic Audio. A summary of the functions and peripherals can be seen below.
| Violet B | Violet C | |
|---|---|---|
| Features | ||
| Bluetooth BR/EDR | ||
| BLE | ||
| LE Audio | ||
| USB | ||
| I2S | ||
| TWI / I2C | ||
| UART 0 / 1 | ||
| SPI | ||
A number of other functions, such as GPIO, timers, IR Rx, etc, can be accessed by multiplexing certain peripherals. See the datasheet for further information.
Pinout
The pinout is as follows.
| Pin Number | Pin Name | Description |
|---|---|---|
| 1 | GND | Ground |
| 2 | GND | Ground |
| 3 | AOR | DAC Analog Out Right |
| 4 | GPIO9 / SPI1 CLK | GPIO 9 | SPI Clock |
| 5 | AOL | DAC Analog Out Left |
| 6 | GPIO10 / SPI1 MISO | GPIO 10 | SPI MISO |
| 7 | GPIO11 / SPI1 MOSI | GPIO 11 | SPI MOSI |
| 8 | GPIO12 / SPI1 SS | GPIO 12 | SPI Chip Select |
| 9 | GND | Ground |
| 10 | 5V | 5V power supply [in] |
| 11 | BAT | 4.1V power supply [out] |
| 12 | GND | Ground |
| 13 | AIR | Analog Input Right |
| 14 | AIL | Analog Input Left |
| 15 | AUX DET | AUX detect |
| 16 | GPIO0 | GPIO 0 |
| 17 | GND | Ground |
| 18 | I2S MCLK | I2S Master Clock |
| 19 | I2S BCLK | I2S Bit Clock |
| 20 | I2S LRCLK | I2S L/R Clock |
| 21 | I2S SDO | I2S Serial Data Out |
| 22 | I2S SDI | I2S Serial Data In |
| 23 | GND | Ground |
| 24 | GPIO1 / UART1 Rx | GPIO 1 | UART 1 Receive |
| 25 | GPIO2 / UART1 Tx | GPIO 2 | UART 1 Transmit |
| 26 | PROG | USB Program select [active low] |
| 27 | GPIO3 / WAKE | GPIO 3 | WAKE function |
| 28 | RST | Reset board [active low] |
| 29 | GPIO4 / UART1 RTS | GPIO 4 | UART 1 Clear To Send |
| 30 | GPIO5 / UART1 CTS | GPIO 5 | UART 1 Ready To Send |
| 31 | GND | Ground |
| 32 | VCC | 3.3V power supply [out] |
| 33 | LED1 | LED 1 drive pin |
| 34 | LED2 | LED 2 drive pin |
| 35 | GND | Ground |
| 36 | USB DP | USB Data Plus |
| 37 | USB DM | USB Data Minus |
| 38 | ADC2 | Low Resolution ADC 2 |
| 39 | ADC1 | Low Resolution ADC 1[1] |
| 40 | VCC | 3.3V power supply [out] |
| 41 | GPIO6 / PWM | GPIO 6 | PWM output |
| 42 | GPIO7 / TWI SCL | I2C Clock |
| 43 | GPIO8 / TWI SDA | I2C Data |
| 44 | GND | Ground |
| 45 | GND | Ground |
If USB ADFU mode cannot be reached by normal means (holding PROG low during a reset), ADC1 can be pulled to ground to forcefully enter this mode. Additionally, R6 on Violet C can be populated to short ADC1 to GND.
Violet C Pin Number Diagram
State Machine
The Violet State Machine is as follows.
For the most part, the State Machine should be self sufficient. APIs can be used to request information about the Bluetooth connection, without affecting the state machine directly. There are only 3 ways the state machine should be manually changed.
- Entering the Discoverable state
- Clearing the pair list (wiping reconnection information)
- Smartphone connections, disconnections, media changes, etc
Deprecated APIs will remain, but may break the state machine behavior.
API Structure
Violet APIs are to follow the following packet structure when sent over UART1.
Packet Structure
For the time being, the Magic value shall remain as 0xAA. Any packets not containing the same value shall be discarded.
Packet lengths are API dependent. The least amount of data a packet can contain is 3 bytes, where the Payload Length shall be set to 1. Note that all packets sent from an MCU to Violet will be responded to, but Violet may send APIs without request.
API Type
| Value | Hex | Description |
|---|---|---|
| ACK | 0x01 | Acknowledge. Indicates that the API has been successfully received. |
| STATUS | 0x02 | Status. Indicates a given state, given the context of the API in question. |
| VOLUME | 0x03 | Volume. Special status used to indicate a change in volume level. |
| SKAA_API | 0x04 | APIs marked with the SKAA_API type are intended to be forwarded from MCU to BLE, or vice versa. |
| NACK | 0xFF | Bad API received, API context dependent. |
API - Power On
ActiveDescription
This API is emitted during boot of Violet C. It can be used to notify that the Violet C is active, or that a reboot has occurred. A reboot may be unintentional, or via an OTA upgrade.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Power Off
DeprecatedDescription
This API was relevant in Violet A, as it had to be externally powered on and off(seperate chipset). This API will still respond, but it will have no effect on Violet C.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Enter Standby
DeprecatedDescription
This API will disconnect any connected devices, stop reconnection, and enter non-discoverable.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Exit Standby
DeprecatedDescription
This API reallows connections to Violet.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Enter Linkback
DeprecatedDescription
This API will start the reconnection process for any devices stored on the pair list.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Enter Discoverable
ActiveDescription
This API will force Violet into a discoverable state, and allows new connections to the module. This API will return an ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Exit Discoverable
DeprecatedDescription
This API cause Violet to enter a non-discoverable state, and will try to reconnect to a device on the pair list, if any. This API will return an ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Clear Pair List
ActiveDescription
This API will disconnect any connected devices, and wipe all reconnection information from NVRAM (effectively clearing the pair list). This API will return an ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Play
ActiveDescription
This API will attempt to stop any media over AVRCP. If the command fails, a NACK will be returned, otherwise, ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
Violet
→
MCU
Not Acknowledge
API - Play
ActiveDescription
This API will attempt to toggle between pause and play over AVRCP. This behaviour is carried over from Violet B. If the command fails, a NACK will be returned, otherwise, ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
Violet
→
MCU
Not Acknowledge
API - Volume Up
ActiveDescription
This API will increment the relative system volume. This API will return an ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Volume Down
ActiveDescription
This API will decrement the relative system volume. This API will return an ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Volume Set
ActiveDescription
This API will set the absolute system volume. This API will return an ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Track Forward
ActiveDescription
This API will attempt to go to the next track over AVRCP. This behaviour is carried over from Violet B. If the command fails, a NACK will be returned, otherwise, ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
Violet
→
MCU
Not Acknowledge
API - Track Back
ActiveDescription
This API will attempt to go to the previous track over AVRCP. This behaviour is carried over from Violet B. If the command fails, a NACK will be returned, otherwise, ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
Violet
→
MCU
Not Acknowledge
API - Request Volume
ActiveDescription
This API will return an ACK containing the volume.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Request Pair List
ActiveDescription
This API will return an ACK containing the Bluetooth Addresses of all devices on the pair list. The Payload Length can be used to return the number of paired devices, and each Bluetooth Address is emitted consecutively. If there are no paired devices, the Payload Length shall be set to 2.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Request State
ActiveDescription
This API will return an ACK containing the system connection state.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - OTA UART Upgrade
ActiveDescription
This API will begin the OTA upgrade process over UART, using the generated ota.bin file. This API returns an ACK. See the programming section for further information.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Disconnect
ActiveDescription
This API disconnects any/all currently connected devices, and returns an ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Update Bluetooth Name
ActiveDescription
This API writes a new Bluetooth BR/EDR name to NVRAM, and returns an ACK. The Payload Length should be equal to the name length in characters + 3. The name should end in a null terminator \0.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Update MAC Address
ActiveDescription
This API writes a new device MAC Address to NVRAM, and returns an ACK. The Payload Length should be equal to 8.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - SKAA API To Violet
ActiveDescription
This API acts as a passthrough for SKAA APIs, forwarding APIs from the MCU to a BLE connection (if available). This API returns an ACK.
MCU
→
Violet
SKAA API
Violet
→
MCU
Acknowledge
API - SKAA API To MCU
ActiveDescription
This API acts as a passthrough for SKAA APIs, forwarding APIs from a BLE connection (if available) to the MCU. This API is one way only.
Violet
→
MCU
SKAA API
API - Set Local Volume Scaling
ActiveDescription
This API sets the local DAC volume, and returns an ACK.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Update Bluetooth LE Name
ActiveDescription
This API writes a new Bluetooth LE Name to NVRAM, and returns an ACK. The Payload Length should be equal to the name length in characters + 3.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Update Nadja LS Version
ActiveDescription
This API writes the current Nadja LS version to NVRAM, and returns an ACK. The Payload Length should be equal to the version length in characters + 3.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Update Hardware ID
ActiveDescription
This API writes the Hardware ID to NVRAM, and returns an ACK. The Payload Length should be equal to the hardware ID length in characters + 3.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Update UUID
ActiveDescription
This API writes the UUID to NVRAM, and returns an ACK. The Payload Length should be equal to the UUID length in characters + 3.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Update Serial Number
ActiveDescription
This API writes the Serial Number to NVRAM, and returns an ACK. The Payload Length should be equal to the Serial Number length in characters + 3. The serial number must be 7–32 printable ASCII characters.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - OTA UART Fast Upgrade
ActiveDescription
This API initiates the OTA Upgrade process over UART, and returns an ACK. The MCU must support switching baud rates, as the fast upgrade runs at 3 MBaud, while the command is sent at 115200. See the programming section for further details.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - OTA UART Very Fast Upgrade
ActiveDescription
This API initiates the OTA Upgrade process over UART, and returns an ACK. The MCU must support switching baud rates, as the very fast upgrade runs at 6 MBaud, while the command is sent at 115200. This API has not been tested, but should theoretically work. See the programming section for further details.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Command Unknown
IncompleteDescription
This API ACKs any non-supported APIs.
Violet
→
MCU
Not Acknowledge
API - Request Metadata Title
ActiveDescription
This API returns the current title metadata, retrieved via AVRCP. If no data is valid, the payload shall be set to 2.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Request Metadata Artist
ActiveDescription
This API returns the current artist metadata, retrieved via AVRCP. If no data is valid, the payload shall be set to 2.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Request Metadata Album
ActiveDescription
This API returns the current album metadata, retrieved via AVRCP. If no data is valid, the payload shall be set to 2.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Request Metadata Duration
ActiveDescription
This API returns the current track duration metadata as a decimal millisecond string, retrieved via AVRCP. If no data is valid, the payload shall be set to 2.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Request Play Status
ActiveDescription
This API returns the current media play status as a 3-byte response. The play status byte is the value returned by the BT manager's media status query.
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge
API - Request Remote Bluetooth Name
ActiveDescription
This API returns the Bluetooth device name of the active A2DP peer (up to 30 characters). If no A2DP device is active, the response payload length is set to 2 (type + API code only).
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge (device connected)
Violet
→
MCU
Acknowledge (no device)
API - Request Remote Bluetooth Address
ActiveDescription
This API returns the 6-byte BD_ADDR of the active A2DP peer. If no A2DP device is active, the response payload length is set to 2 (type + API code only).
MCU
→
Violet
Command
Violet
→
MCU
Acknowledge (device connected)
Violet
→
MCU
Acknowledge (no device)
Programming
There are 2 primary ways to program Violet C.
- Via ADFU over USB
- Via OTA over UART
USB
The only 2 requirements to program violet is the 5V power supply, and USB data lines (DP, DM).
If the Violet C has not been programmed before, ADFU(Actions Device Firmware Upgrade) will be entered automatically. While in this mode, the MultiMedia Product Tool by Actions can be used to flash a .fw file.
If the Violet has been programmed prior, there are 2 ways to intentionally enter ADFU. First, holding the PROG pin active low while resetting the board (via RST) will initiate ADFU. The second way to intentionally enter ADFU is to shortADC1 to Ground. This can be manually achevied by populating R6 on Violet C, and removing after flashing.
Once in ADFU mode, the number of USB devices will increase on the MultiMedia Product Tool, and it will classify as ADFU, not UDISK.
When the Violet is "Ready", you can select the desired .fw file, and hit the large download arrow.
When the download has completed successfully, the connected device will show "Successful(offline)". From this point, resetting the Violet will cause it to enter normal operation. Other programming options can be selected on the right side of the tool, and hovering over will provide descriptions hints.
UART
Programming via UART effectively transfers a firmware binary (.bin) to Violet, which flashes itself once the transfer is complete.
The exchange consists of three main phases: Initialization, Handshake,
and Data Transfer. Only the host may begin the transfer via the OTA UART Upgrade API (API Code 0x13 or 0x3F). Note that the "Very Fast" requires a baude rate of 600000, and has not been tested due to hardware limitiations.
1. UART API Update Trigger
The default baud rate is determined by the API in question. If a higher baud rate is selected, both sides must do a switch in conjunction with eachother. A buad rate of 3 MBaud is suggested, as it reduces flashing time from 3 minutes to 30 seconds. No other APIs should be sent after this API is transferred, otherwise the process may freeze, and reset is required. This applies to Bluetooth events as well, so ensure that no devices are connected during this process.
If a higher baud is selected, the baud rate switch must be complete immediately after the API transfer.
2. Handshake
The purpose of the handshake is to begin the data transfer.
3. Data Transfer
PULLDATA Command Packet
Once the handshake is complete, Violet will begin to emit commands for data.
| Bytes | Type | Field |
|---|---|---|
| 0 – 7 | char[8] |
Command name (ASCII, zero-padded) |
| 8 – 11 | uint32_t little-endian |
Sequence number |
| 12 – 15 | uint32_t little-endian |
Byte offset in firmware image |
| 16 – 19 | uint32_t little-endian |
Number of Bytes requested |
PULLDATA Response
The host shall respond to the PULLDATA request with the requested data, and a CRC-32 check.
| Bytes | Field |
|---|---|
| 0 – 3 | CRC-32 of firmware[offset : offset+len−1] |
| 4 – 7 | Echo of the request sequence number (little-endian) |
| 8 – 8+len−1 | Raw firmware data (len bytes) |
REPORT01 Command Packet
After all chunks have been pulled successfully, the device sends a REPORT01 command to signal it
has received the entire image.
| Bytes | Type | Field |
|---|---|---|
| 0 – 7 | char[8] |
Command name (ASCII, zero-padded) |
| 8 – 11 | uint32_t little-endian |
Sequence number |
| 12 – 15 | uint32_t little-endian |
0x0000 |
| 16 – 19 | uint32_t little-endian |
0x0000 |
REPORT01 Response
Once the response is received, the OTA update is considered complete on the Host side.
| Bytes | Field |
|---|---|
| 0 – 3 | CRC-32 of the ASCII string "REPORT01" |
| 4 – 7 | Echo of the sequence number (little-endian) |
| 8 – 15 | ASCII string "REPORT01" |
After the data transfer is complete, allow up to a minute for the Violet to complete firmware upgrades. Interrupting this process may cause the Violet to enter an un-recoverable state, except via ADFU. A Power On API can be used to indicate when the process is complete.
CRC-32 Algorithm
static const uint32_t s_crc32[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
uint32_t VioletProgrammer::Crc32(uint32_t crc, const uint8_t* ptr, uint32_t buf_len) {
uint32_t crcu32 = ~crc;
while (buf_len--) {
uint8_t b = *ptr++;
crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
}
return ~crcu32;
}
Miscellaneous
Useful Structures
typedef struct {
uint8_t magic;
uint8_t length;
std::array payload; // Type (1 byte) + API (1 byte) + up to 253 bytes of data
} violet_uart_api_t;
enum class VioletMagic : uint16_t {
VioletB = 0xAA,
VioletC = 0xCC,
NotApplicable = 0xFF
};
/* VIOLET C TYPE */
enum class VioletAPIType : uint8_t {
Event = 0x00,
Ack = 0x01,
Status = 0x02,
Volume = 0x03,
SkaaAPI = 0x04,
Nack = 0xFF
};
/* VIOLET CONNECTION STATE */
enum class ConnState {
Off = 0x00, // Radio is considered off.
PowerOn = 0x01, // Radio has turned on. This is more so an event, as the state will change almost immediately after.
Reconnecting = 0x02, // Radio is attempting to connect to a device found on the pair list, based on reconnect policy.
Discoverable = 0x03, // Radio is discoverable, AND other states are invalid.
Connected = 0x04, // Radio has an active connection to another device.
Standby = 0x06, // Radio is on, but not discoverable or connectable.
Pairing, // Another device has initiated pairing.
Connecting, // Radio is in the process of connecting to another device.
Disconnecting, // Radio is in process of disconnecting from another device (intentional).
};
/* VIOLET EVENTS */
enum class VioletEvent : uint8_t {
PowerOn = 0x00,
DeviceConnected = 0x01,
DeviceDisconnected = 0x02,
TrackChanged = 0x03,
MetadataUpdated = 0x04,
TransportBr = 0x05,
TransportLe = 0x06,
MediaConnected = 0x07
};
/* VIOLET B APIs */
enum class VioletAPI : uint8_t {
PowerOn = 0x01,
PowerOff = 0x02,
EnterStandby = 0x03,
ExitStandby = 0x04,
EnterLinkback = 0x05,
EnterDiscoverable = 0x06,
ExitDiscoverable = 0x07,
ClearPairedList = 0x08,
Play = 0x09,
Pause = 0x0A,
VolumeUp = 0x0B,
VolumeDown = 0x0C,
VolumeSet = 0x0D,
NextTrack = 0x0E,
PrevTrack = 0x0F,
RequestVolume = 0x10,
RequestPairedList = 0x11,
RequestState = 0x12,
OtaUartUpgrade = 0x13,
Disconnect = 0x14,
UpdateBtName = 0x15,
UpdateMac = 0x16,
SkaaApiToViolet = 0x17,
SkaaApiToNls = 0x18,
SetLocalVolumeScaling = 0x19,
UpdateBleName = 0x1A,
UpdateNlsVersion = 0x1B,
UpdateHwid = 0x1C,
UpdateUuid = 0x1D,
UpdateSerialNumber = 0x1E,
RequestMetadataTitle = 0x20,
RequestMetadataArtist = 0x21,
RequestMetadataAlbum = 0x22,
RequestMetadataDuration = 0x23,
RequestPlayStatus = 0x24,
RequestRemoteBtName = 0x25,
RequestRemoteBtAddr = 0x26,
OtaUartFastUpgrade = 0x3F,
OtaUartVeryFastUpgrade = 0x40,
CommandUnknown = 0xFF
};
enum class PlayStatus : uint8_t {
Inactive = 0,
Paused,
Playing
};
Changelog
What's new in each release
v1 2026-05-29
- Create online documentation
v1 2026-05-29
- Complete online documentation