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.
Contents
[ps2id url='#setup']Setup[/ps2id]
[ps2id url='#include']#include[/ps2id] - including the library
[ps2id url='#declare']RN52 rn52()[/ps2id] - declaring an instance of the library
[ps2id url='#begin']begin()[/ps2id] - begin communication with the RN52
[ps2id url='#general']General Commands[/ps2id]
[ps2id url='#reboot']reboot()[/ps2id] - reboot the RN52
[ps2id url='#setDiscoverability']setDiscoverability()[/ps2id] - sets whether new devices can discover RN52
[ps2id url='#toggleEcho']toggleEcho()[/ps2id] - toggles the command interface echo
[ps2id url='#factoryReset']factoryReset()[/ps2id] - perform a factory reset
[ps2id url='#idlePowerDownTime']idlePowerDownTime()[/ps2id] - set or get the idle power down time
[ps2id url='#name']name()[/ps2id] - set or get the connection name for the RN52
[ps2id url='#volumeOnStartup']volumeOnStartup()[/ps2id] - set or get the startup volume
[ps2id url='#serial']Serial Commands[/ps2id]
[ps2id url='#println']println()[/ps2id] - send data to the RN52 with a newline character
[ps2id url='#print']print()[/ps2id] - send data to the rn52 without new line character
[ps2id url='#available']available()[/ps2id] - get the number of bytes waiting to be read from the RN52
[ps2id url='#audio']Audio Commands[/ps2id]
[ps2id url='#volumeUp']volumeUp()[/ps2id] - Turns the volume up
[ps2id url='#volumeDown']volumeDown()[/ps2id] - Turns the volume down
[ps2id url='#playPause']playPause()[/ps2id] - Plays/Pauses the track
[ps2id url='#nextTrack']nextTrack()[/ps2id] - Skips to the next track
[ps2id url='#prevTrack']prevTrack()[/ps2id] - Skips to the previous track
[ps2id url='#trackTitle']trackTitle()[/ps2id] - Gets the track title
[ps2id url='#album']album()[/ps2id] - Gets the album
[ps2id url='#artist']artist()[/ps2id] - Gets the artist
[ps2id url='#genre']genre()[/ps2id] - Gets the genre
[ps2id url='#trackNumber']trackNumber()[/ps2id] - Gets the track number
[ps2id url='#trackCount']trackCount()[/ps2id] - Gets the total track count
[ps2id url='#getMetaData']getMetaData()[/ps2id] - Gets the entire metadata
[ps2id url='#gpio']GPIO Commands[/ps2id]
[ps2id url='#gpioPinMode']GPIOPinMode()[/ps2id] - Change the pin mode of an RN52 GPIO pin
[ps2id url='#gpioDigitalWrite']GPIODigitalWrite()[/ps2id] - Change the state of an RN52 GPIO Pin
[ps2id url='#gpioDigitalRead']GPIODigitalRead()[/ps2id] - Read the state of an RN52 GPIO Pin
[ps2id url='#eventstatusreg']Event/Status Register[/ps2id]
[ps2id url='#getEventReg']getEventReg()[/ps2id] - Read the current value of the event register
[ps2id url='#trackChanged']trackChanged()[/ps2id] - Determine if the track has changed
[ps2id url='#isConnected']isConnected()[/ps2id] - Determine if a device is connected
[ps2id url='#extended-functions']RN52 Extended Features - Functions[/ps2id]
[ps2id url='#AVRCPButtons']AVRCPButtons()[/ps2id] - GPIO Buttons to control music
[ps2id url='#powerUpReconnect']powerUpReconnect()[/ps2id] - RN52 reconnecting on startup
[ps2id url='#startUpDiscoverable']startUpDiscoverable()[/ps2id] - RN52 discoverable on startup
[ps2id url='#rebootOnDisconnect']rebootOnDisconnect()[/ps2id] - RN52 rebooting when disconnected from
[ps2id url='#volumeToneMute']volumeToneMute()[/ps2id] - Mute volume tones
[ps2id url='#systemTonesDisabled']systemTonesDisabled()[/ps2id] - Disable system tones
[ps2id url='#powerDownAfterPairingTimout']powerDownAfterPairingTimout()[/ps2id] - Power down after a pairing timeout
[ps2id url='#resetAfterPowerDown']resetAfterPowerDown()[/ps2id] - Reset after a power down
[ps2id url='#reconnectAfterPanic']reconnectAfterPanic()[/ps2id] - Reconnect after a panic situation
[ps2id url='#tonesAtFixedVolume']tonesAtFixedVolume()[/ps2id] - Fix all system tones at a single volume
[ps2id url='#autoAcceptPasskey']autoAcceptPasskey()[/ps2id] - Disables the passkey feature
[ps2id url='#extended-advanced']RN52 Extended Features - Advanced[/ps2id]
[ps2id url='#setExtFeatures']setExtFeatures()[/ps2id] - Sets the extended features register
[ps2id url='#getExtFeatures']getExtFeatures()[/ps2id] - Gets the contents of the extended features register
[ps2id url='#audiorouting']A2DP Audio Routing[/ps2id]
[ps2id url='#A2DPRoute']A2DPRoute()[/ps2id] - Get or set the A2DP routing
[ps2id url='#sampleWidth']sampleWidth()[/ps2id] - Get or set the sample width of the output
[ps2id url='#sampleRate']sampleRate()[/ps2id] - Get or set the sample rate of the output
Setup
#include <RN52.h>
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);
Parameters:
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.
begin(baudRate);
Parameters:
long baudRate - the baud rate of communication
Returns:
None
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
[ps2id url='#contents']Back to contents[/ps2id]
General Commands
reboot();
Parameters:
None
Returns:
None
rn52.reboot(); //Reboots the RN52.
setDiscoverability(discoverabilityState);
Parameters:
boolean discoverabilityState - TRUE for discoverable, FALSE for not discoverable
Returns:
None
rn52.setDiscoverability(1); //Sets the module discoverable
toggleEcho();
Parameters:
None
Returns:
None
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.
rn52.toggleEcho();
factoryReset();
Parameters:
None
Returns:
None
Does what it says on the tin, requires a restart after use.
rn52.factoryReset()
idlePowerDownTime(Optional: newTime);
Parameters (OPTIONAL):
int newTime - the idle power down time
Returns:
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);
Parameters (OPTIONAL):
String newName - The new name for the RN52
boolean normalised - Whether the name is normalised
Returns:
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
volumeOnStartup(Optional: newVolume);
Parameters (OPTIONAL):
int newVolume - The new output volume for the RN52
Returns:
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.
[ps2id url='#contents']Back to contents[/ps2id]
Serial Commands
println(dataToSend);
Parameters:
String dataToSend - the data which will be sent
Returns:
None
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);
Parameters:
String dataToSend - the data which will be sent
Returns:
None
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
available();
Parameters:
None
Returns:
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)
[ps2id url='#contents']Back to contents[/ps2id]
Audio Commands
Most of these commands are fairly self-explanatory.
volumeUp();
Parameters:
None
Returns:
None
rn52.volumeUp();
volumeDown();
Parameters:
None
Returns:
None
rn52.volumeDown();
playPause();
Parameters:
None
Returns:
None
rn52.playPause();
nextTrack();
Parameters:
None
Returns:
None
rn52.nextTrack();
prevTrack();
Parameters:
None
Returns:
None
rn52.prevTrack();
trackTitle();
Parameters:
None
Returns:
String - the current track title
String title = rn52.trackTitle();
album();
Parameters:
None
Returns:
String - the current track album
String album = rn52.album();
artist();
Parameters:
None
Returns:
String - the current track artist
String artist = rn52.artist();
genre();
Parameters:
None
Returns:
String - the current genre
String genre = rn52.genre();
trackNumber();
Parameters:
None
Returns:
int- the number of the current track in the queue
int trackNumber = rn52.trackNumber();
trackCount();
Parameters:
None
Returns:
int- the number of the final track in the queue
int trackCount = rn52.trackCount();
getMetaData();
Parameters:
None
Returns:
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();
[ps2id url='#contents']Back to contents[/ps2id]
GPIO Commands
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.
GPIOPinMode(pin, state);
Parameters:
int pin - the GPIO pin to alter
boolean state - TRUE for output, FALSE for input
Returns:
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
GPIODigitalWrite(pin, state);
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.
Parameters:
int pin - the GPIO pin to alter
boolean state - TRUE for high, FALSE for low
Returns:
None
rn52.GPIODigitalWrite(12, 0); //Writes pin 12 low
GPIODigitalRead(pin);
Parameters:
int pin - the GPIO pin to read
Returns:
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
[ps2id url='#contents']Back to contents[/ps2id]
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.
Parameters (OPTIONAL):
boolean state - the new state of the option
Returns:
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.
AVRCPButtons();
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.
[ps2id url='#extended-functions']See above for usage[/ps2id]
rn52.AVRCPButtons(1); //turn AVRCP buttons on. boolean state = rn52.AVRCPButtons(); //reads the current state of the AVRCP buttons into the state variable.
GPIO10 | Volume Down |
GPIO11 | Previous Track |
GPIO12 | Next Track |
GPIO13 | Play/Pause |
GPIO5 | Volume Up |
powerUpReconnect();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Determines whether the RN52 will attempt a reconnect on power up, it will attempt to reconnect with any device previously paired.
startUpDiscoverable();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Determines whether the RN52 is discoverable on start-up.
rebootOnDisconnect();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Determines whether the RN52 will restart after a disconnect, this is useful as after a disconnect the RN52 will not be discoverable.
volumeToneMute();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Mutes the volume tone (a tone which sounds whenever you change the volume).
systemTonesDisabled();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Disables the system tones, which will sound on power up and on connection.
powerDownAfterPairingTimout();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Enables the feature which will power down the RN52 after pairing is unsuccessful after a certain time.
resetAfterPowerDown();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Enables the reset after power down on the RN52, which will cause it to reset on every power cycle.
reconnectAfterPanic();
[ps2id url='#extended-functions']See above for usage[/ps2id]
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.
tonesAtFixedVolume();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Keeps the tones at a fixed volume independent of the media volume.
autoAcceptPasskey();
[ps2id url='#extended-functions']See above for usage[/ps2id]
Disables the passkey.
[ps2id url='#contents']Back to contents[/ps2id]
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
Returns:
None
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.
getExtFeatures();
Parameters:
None
Returns:
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.
[ps2id url='#contents']Back to contents[/ps2id]
Event/Status Register
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.
getEventReg();
Parameters:
None
Returns:
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.
trackChanged();
Parameters:
None
Returns:
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.
isConnected();
Parameters:
None
Returns:
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.
[ps2id url='#contents']Back to contents[/ps2id]
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.
A2DPRoute();
Parameters (OPTIONAL):
int - an indicator of the new routing to be used (see below)
Returns:
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
sampleWidth();
Parameters (OPTIONAL):
int - an indicator of the new sample width to be used (see below)
Returns:
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
sampleRate();
Parameters (OPTIONAL):
int - an indicator of the new sample rate to be used (see below)
Returns:
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
[ps2id url='#contents']Back to contents[/ps2id]