This Arduino library was originally written for our development board, the Bluetooth Audio Link, which can be found on our tindie store. However it will work for any RN52 based project, with the serial port connected to an Arduino. The library was adapted from the Software Serial library by Thomas Cousins and additional functions written by Thomas McQueen. For any help or queries about the library, please email: thom @ doayee dot co dot uk
If there is a function not implemented by the library which Microchip document in their guide, you can use RN52.println() to send characters as if in a terminal application.
#include - including the library
RN52 rn52() - declaring an instance of the library
begin() - begin communication with the RN52
reboot() - reboot the RN52
setDiscoverability() - sets whether new devices can discover RN52
toggleEcho() - toggles the command interface echo
factoryReset() - perform a factory reset
idlePowerDownTime() - set or get the idle power down time
name() - set or get the connection name for the RN52
volumeOnStartup() - set or get the startup volume
println() - send data to the RN52 with a newline character
print() - send data to the rn52 without new line character
available() - get the number of bytes waiting to be read from the RN52
volumeUp() - Turns the volume up
volumeDown() - Turns the volume down
playPause() - Plays/Pauses the track
nextTrack() - Skips to the next track
prevTrack() - Skips to the previous track
trackTitle() - Gets the track title
album() - Gets the album
artist() - Gets the artist
genre() - Gets the genre
trackNumber() - Gets the track number
trackCount() - Gets the total track count
getMetaData() - Gets the entire metadata
GPIOPinMode() - Change the pin mode of an RN52 GPIO pin
GPIODigitalWrite() - Change the state of an RN52 GPIO Pin
GPIODigitalRead() - Read the state of an RN52 GPIO Pin
getEventReg() - Read the current value of the event register
trackChanged() - Determine if the track has changed
isConnected() - Determine if a device is connected
RN52 Extended Features - Functions
AVRCPButtons() - GPIO Buttons to control music
powerUpReconnect() - RN52 reconnecting on startup
startUpDiscoverable() - RN52 discoverable on startup
rebootOnDisconnect() - RN52 rebooting when disconnected from
volumeToneMute() - Mute volume tones
systemTonesDisabled() - Disable system tones
powerDownAfterPairingTimout() - Power down after a pairing timeout
resetAfterPowerDown() - Reset after a power down
reconnectAfterPanic() - Reconnect after a panic situation
tonesAtFixedVolume() - Fix all system tones at a single volume
autoAcceptPasskey() - Disables the passkey feature
RN52 Extended Features - Advanced
setExtFeatures() - Sets the extended features register
getExtFeatures() - Gets the contents of the extended features register
A2DP Audio Routing
A2DPRoute() - Get or set the A2DP routing
sampleWidth() - Get or set the sample width of the output
sampleRate() - Get or set the sample rate of the output
Whenever you are using the RN52 library, you must include it at the top of your sketch. This allows the IDE to recognise commands from the library.
RN52 rn52(RX, TX);
int RX - the Arduino pin used as RX
int TX - the Arduino pin used as TX
To begin using the library you must first define the class, in this case ‘rn52’, but you could call it anything. The pins you are connecting to the RN52 with must be specified in the RX and TX fields.
The library is based off the SoftwareSerial library, and the same limitations apply when using it:
- If using multiple software serial ports, only one can receive data at a time.
- Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69).
- Not all pins on the Leonardo and Micro support change interrupts, so only the following can be used for RX: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).
RN52 rn52(10,11); //Set RX to 10 and TX to 11
From now on all commands must start with your class name, then a dot. This links the command to the library, and without it the sketch will not be able to compile.
long baudRate - the baud rate of communication
To start communication with the RN52, you must use the begin command. Within the begin command you must specify the baud rate you are communicating at. We recommend using a baud rate of 38400 or below, as above this the library can be temperamental due to the interrupt service routines onboard the AVR micro-controllers. If you are using the library with a BAL then the RN52 will already be set to communicate at 38400, but if not you will have to set this yourself.
rn52.begin(38400); //Begin communication with the RN52 at 38400baud
rn52.reboot(); //Reboots the RN52.
boolean discoverabilityState - TRUE for discoverable, FALSE for not discoverable
rn52.setDiscoverability(1); //Sets the module discoverable
Command used to toggle the echo feature of the RN52, which simply sends back every character you send it, giving you a real time view of what you are sending to it. Useful for debugging code.
Does what it says on the tin, requires a restart after use.
int newTime - the idle power down time
None - in the case that a new time is set
int - the current idle power down time, in the case no new time is set
The idle power down time is the time it takes for the RN52 to power down when it is receiving no input. By default it is set to 0, which means it will never power down.
rn52.idlePowerDownTime(30); //Sets the idle power down time to 30 secs int i = rn52.idlePowerDownTime(); //reads the idle power down time into the integer i.
name(Optional: “newName”, normalised or not);
String newName - The new name for the RN52
boolean normalised - Whether the name is normalised
None - in the case that a new name is set
String - the current name, in the case no new name is set
Command used to either set, or read the name of the RN52. If the “New Name” field is left blank it will return the current name of the RN52 as a String. If the “New Name” field is included, you must specify whether the name should be normalized or not (appended with the latter four digits of the MAC address of the RN52.
rn52.name(“BAL-New”, 0) //Sets the name to BAL-New, not normalized String currentName = rn52.name(); //Sets the string currentName to the current name of the RN52
int newVolume - The new output volume for the RN52
None - in the case that a new volume is set
int - the current volume, in the case no new volume is set
Command used to either set, or read the volume level on the RN52 start-up. If the New Volume field is left blank it will return the volume as an int. Volume is between 1 and 15.
rn52.volumeOnStartup(10); //Sets the volume on start-up to 10. int i = rn52.volumeOnStartup(); //Sets the integer i to the current volume on start-up.
String dataToSend - the data which will be sent
Command used to send the raw ascii data input to the RN52, as you would if you were using a command line interface.
rn52.println(“v”); //Request RN52 firmware version
print(“data to send);
String dataToSend - the data which will be sent
Command used to send the raw ascii data input to the RN52, as you would if you were using a command line interface. Does not include the newline character which is necessary for the RN52 to accept the command. For this use println (see above).
rn52.print(“v”); //send “v” character to RN52
int - the number of available bytes to read
Command used to return the number of bytes of data in the input buffer sent from the RN52.
int i = rn52.available(); //sets an integer i to the number of bytes sent from the RN52 since data was last read ie. //After a command is sent the RN52 responds with “AOK” which in this case would set i to 3 //(one byte per character)
Most of these commands are fairly self-explanatory.
String - the current track title
String title = rn52.trackTitle();
String - the current track album
String album = rn52.album();
String - the current track artist
String artist = rn52.artist();
String - the current genre
String genre = rn52.genre();
int- the number of the current track in the queue
int trackNumber = rn52.trackNumber();
int- the number of the final track in the queue
int trackCount = rn52.trackCount();
String - the full MetaData
Outputs the entire available MetaData as one long string. This may vary depending upon the audio source capabilities. It may include genre or track length, in addition to title, album and artist. Be careful with very long track names, the Arduino UNO especially can fail to handle a string this long if not considered properly.
String data = rn52.getMetaData();
Only GPIO pins 5, 6, 10, 11, 12, and 13 are available for use as GPIO on the BAL. The others have separate reserved functions. Changing the mode on any pins other than these will have no effect on the RN52, as the library prohibits it.
int pin - the GPIO pin to alter
boolean state - TRUE for output, FALSE for input
boolean - TRUE for success, FALSE for error
This command is used to set the pinMode of the desired pin. It works exactly like the normal pinMode command used by the Arduino IDE. The pin field specifies which pin you are declaring as an input or output, and the state field specifies which state it should be.
rn52.GPIOPinMode(12, 1); //Sets pin 12 to an output
This command is used to set an output as logic high or logic low, or to enable or disable the internal pull-up resistors on an input. It works exactly like the normal digitalWrite command used by the Arduino IDE. The pin field specifies which pin you want to change, and the state field specifies which state to change it to.
int pin - the GPIO pin to alter
boolean state - TRUE for high, FALSE for low
rn52.GPIODigitalWrite(12, 0); //Writes pin 12 low
int pin - the GPIO pin to read
boolean - TRUE for high, FALSE for low
This command reads back the state of any pin, output or input. It is a boolean function, so it returns either a 1 or a 0 depending on the state of the pin (1 for HIGH, 0 for LOW).
while(rn52.GPIODigitalRead(11)); //Waits while pin 11 is high
Extended Features - Functions
These commands all alter the extended features of the RN52. They all accept either a Boolean input (1 or 0 – 1 for true, 0 for false), or read back the current state of that particular feature.
boolean state - the new state of the option
None - in the case where a new state was written
boolean - the current state, in the case where no parameters specified
This format follows for all the following commands.
This setting converts certain GPIO pins into dedicated buttons for controlling volume and tracks, as well as a play/pause button. Buttons should be connected from the module to ground. Internal pull-up resistors are present in the RN52.
rn52.AVRCPButtons(1); //turn AVRCP buttons on. boolean state = rn52.AVRCPButtons(); //reads the current state of the AVRCP buttons into the state variable.
Determines whether the RN52 will attempt a reconnect on power up, it will attempt to reconnect with any device previously paired.
Determines whether the RN52 is discoverable on start-up.
Determines whether the RN52 will restart after a disconnect, this is useful as after a disconnect the RN52 will not be discoverable.
Mutes the volume tone (a tone which sounds whenever you change the volume).
Disables the system tones, which will sound on power up and on connection.
Enables the feature which will power down the RN52 after pairing is unsuccessful after a certain time.
Enables the reset after power down on the RN52, which will cause it to reset on every power cycle.
Panic is a mode the RN52 enters when it encounters a situation it has not been programmed for (like an overload of data). This feature enables the RN52 to reconnect after entering panic mode.
Keeps the tones at a fixed volume independent of the media volume.
Disables the passkey.
Extended Features - Advanced
All the previous functions rely on the following two functions to operate correctly, if you’d rather edit the 16 bit Hexadecimal value yourself, you can use the following two functions to achieve this.
setExtFeatures(Option 1: 16-Bit Hex Value. Option 2: Boolean State, Int bit);
Parameters OPTION 1:
short settings - a new extended features setting written as a two-byte hex value
Parameters OPTION 2:
boolean state - the new state of the bit you are setting
int bit - the index of the bit
This command can be used to either set a new hex value, or to alter the state of a particular bit in the hex value. The bits are as follows:
Bit 0 – Enable AVRCP buttons Bit 1 – Enable reconnect on power-on Bit 2 – Bluetooth Discoverable on start up Bit 3 – Codec indicators PIO7 (AAC) and PIO6 (aptX) Bit 4 – Reboot after disconnect (otherwise must power cycle) Bit 5 – Mute volume up/down tones Bit 6 – Enable voice command button on PIO4 Bit 7 – Disable system tones Bit 8 – Power off after pairing timeout Bit 9 – Reset after power off Bit 10 – Enable list reconnect after panic Bit 11 – Enable latch event indicator PIO2 Bit 12 – Enable track change event Bit 13 – Enable tones playback at fixed volume Bit 14 – Enable auto-accept passkey in Keyboard I/O Authentication mode Bit 15 – Blank Bit 16 – Blank
rn52.setExtFeatures(0x50F6); //Set the extended features hex to 50F6. rn52.setExtFeatures(1, 7); //Disable the system tones.
Short - the two-byte value of the extended features
This command returns the current value of the extended features. It is returned as a short i.e. two byte (16 bit) value.
Serial.println(rn52.getExtFeatures(), HEX); //Prints the current extended features value as a hexadecimal //value to the Serial port from the Arduino.
The RN52 has a register for monitoring statuses and events as documented on page 35 of their official command guide. The implementation of this within the RN52 Arduino library is as follows. Note that in the official RN52 command guide Byte 0 refers to the most significant byte, but Bit 0 within that refers to the least significant bit. The event bits (11 & 12) in byte 0 are cleared whenever the register is requested from the device, this is handled by the library for all our functions that use it, and so polling the track change will still return accurately even if other requests have been made since the event.
Short - the two byte value of the event/status register
The bits are as follows:
(Byte 1) Bit 0 – Bits 0-3 indicate the connection state. See below for a listing of the possible states Bit 1 – Above Bit 2 – Above Bit 3 – Above Bit 4 – HFP audio volume level change from audio gateway (phone) Bit 5 – HFP audio microphone level change from audio gateway (phone) Bit 6 – Reserved Bit 7 – Reserved (Byte 0) Bit 8 – iAP wireless active connection to remote device Bit 9 – SPP active connection to remote device Bit 10 – A2DP active connection to remote device Bit 11 – HFP/HSP active connection to remote device Bit 12 – Caller ID notification event from audio gateway Bit 13 – Track change event notification Bit 14 – Reserved Bit 15 – Reserved
The connection state (Bits 0-3 of Byte 1 as described above) is interpreted as follows :
Value 0 – Limbo - Logically off, but physically on 1 – Connectable - The module is connectable, page scanning 2 – Connectable and discoverable - The module is connectable and discoverable, page and inquiry scanning 3 – Connected The module is connected to an audio gateway 4 – Outgoing call established - The connected audio gateway has an outgoing call in progress 5 – Incoming call established - The connected audio gateway has an active call in progress and the audio is in the headset 6 – Active call - The connected audio gateway has an active call in progress and the audio is in the headset 7 – Test mode - The headset is in Test mode 8 – Three-way call waiting - The connected audio gateway has an active call and a second call on hold 9 – Three-way call on hold - The connected audio gateway has an active call and a second call on hold 10 – Three-way call multi-call - The connected audio gateway has an active call and a second call on hold 11 – Incoming call on hold - The connected audio gateway has an incoming call on hold 12 – Active call - The connected audio gateway has an active call and the audio is in the handset 13 – Audio streaming - The headset is streaming A2DP audio 14 – Low battery - The system has a low battery
short state = rn52.getEventReg(); //Returns the event register as a short.
bool - TRUE if the audio track has changed since the last call to this function, FALSE otherwise
boolean trackChanged = rn52.trackChanged(); //Returns a bool indicating whether the audio track has changed.
bool - TRUE if there is a Bluetooth device connected, FALSE otherwise
This function tests if any of Bits 8-11 are true, and returns true if that is the case.
boolean isConnected = rn52.isConnected(); //Returns a bool indicating whether there is an active Bluetooth connection.
A2DP Audio Output Routing
The RN52 by default outputs audio to the analog pins to be amplified by your own circuitry, however it is possible to redirect this to a digital output to be used as input to another system in the form of I2S or S/PDIF. You are also able to control the sample rate and the sample width.
int - an indicator of the new routing to be used (see below)
int - the current indicator of the routing in use (see below) - returned if no new state was written
none - in the case that a new state was written
The indicators are as follows:
0 - Analog Routing (default)
1 - I2S Output
3 - S/PDIF Output
4 - Intercom DAC mode
int currentRouting = rn52.A2DPRoute(); //Returns the current audio routing as an int rn52.A2DPRoute(1); //sets the audio routing to I2S
int - an indicator of the new sample width to be used (see below)
int - the current indicator of the sample width in use (see below) - returned if no new sample width was written
none - in the case that a new sample width written
The indicators are as follows:
0 - 24 bits per sample
1 - 32 bits per sample
int currentSampleWidth = rn52.sampleWidth(); //Returns the current sample width as an int rn52.sampleWidth(1); //sets the sample width to 32 bits per sample
int - an indicator of the new sample rate to be used (see below)
int - the current indicator of the sample rate in use (see below) - returned if no new sample rate was written
none - in the case that a new sample rate written
The indicators are as follows:
0 - 8K samples per second
1 - 32K samples per second
2 - 44K1 samples per second
3 - 48K samples per second
int currentSampleRate = rn52.sampleRate(); //Returns the current sample rate indicator as an int rn52.sampleRate(1); //sets the sample rate to 32K samples per second