Since I've been doing a lot of work with BLE this summer, I thought it would be appropriate to add a BLE interface to my Arty S7 project for the challenge. I initially thought about wiring up a BLE UART board that I had available, either a DSD Tech HM-19 that uses the Ti CC2640 chip or an Adafruit BLE Friend that uses a Nordic nRF51822 chip, but I noticed that the PmodBLE module was available - I just had to wait a week or so to get one. The PmodBLE uses a Microchip RN4871 chip and I haven't used a Microchip BLE part before, so I thought I'd give it a try. It would be a lot cleaner interface and worst case I could fall back to one of the other boards.
It turns out that incorporating the PmodBLE has been a lot bigger task than I had anticipated. The PmodBLE is in Digilent's Vivado Pmod IP library and the previous Pmods were not a problem other than generating "Critical Warnings" in Vivado because the Pmod IP hasn't been updated for Xilinx tools beyond the 2019.1-2 version.
I didn't have any problems adding the PmodBLE in Vivado other than the Critical Warnings.
Here is the Block Diagram with the PmodBLE incorporated:
Zoomed in to show the IO:
I encountered problems when I tried to create an application program in Vitis. For some reason Vitis could not find the necessary include file "PmodBLE.h", so the application would not compile. I verified that the driver files were included in the hardware file exported from Vivado. So, it must be a path or configuration issue. I'll need to do some hunting to find it.
I decided that I should first verify that the PmodBLE IP would work if I used it on its own without the other Pmods. So, I went back to Vivado and simplified the design.
Exported the hardware file to Vitis - and now everything compiled correctly.
The PmodBLE library is fairly sparse. It implements the following basic functions to configure the interface and implement the UART send/receive:
void BLE_Begin(PmodBLE* InstancePtr, u32 GPIO_Address, u32 UART_Address, u32 AXI_ClockFreq, u32 Uart_Baud);
int BLE_RecvData(PmodBLE* InstancePtr, u8 *Data, int nData);
int BLE_SendData(PmodBLE* InstancePtr, u8 *Data, int nData);
void BLE_ChangeBaud(PmodBLE* InstancePtr, int baud);
void BLE_WriteRTS(PmodBLE* InstancePtr, u8 enable);
int BLE_ReadCTS(PmodBLE* InstancePtr);
void BLE_SetReset(PmodBLE* InstancePtr, u8 Value);
int BLE_IsConnected(PmodBLE* InstancePtr);
I discovered that the RN4871 as a GATT Server hosts the Microchip Transparent UART Service by default. The Transparent UART Service provides a simple bidirectional data transfer service. It defines two characteristics for data communication, one for receiving data with the Write property and the other for sending data with the Notify property. So, getting it to work seemed like it would be simple since the service properties and UUIDs are preconfigured.
Service Name |
UUID |
Microchip Transparent UART |
49535343-FE7D-4AE5-8FA9-9FAFD205E455 |
Characteristic Name |
UUID |
Properties |
Microchip Transparent UART TX |
49535343-1E4D-4BD9-BA61-23C647249616 |
Notify, Write, Write without response |
Client Characteristic Descriptor |
|
Read, Write |
Microchip Transparent UART RX |
49535343-8841-43F4-A8D4-ECBE34729BB3 |
Write, Write without response |
The example program included with the IP illustrates this simplicity.
PmodBLE_v1_0/examples/main.c
/******************************************************************************/ /* */ /* main.c -- Example program using the PmodBLE IP */ /* */ /******************************************************************************/ /* Author: Arthur Brown */ /* */ /******************************************************************************/ /* File Description: */ /* */ /* This demo continuously polls the Pmod BLE and host development board's */ /* UART connections and forwards each character from each to the other. */ /* */ /******************************************************************************/ /* Revision History: */ /* */ /* 10/04/2017(artvvb): Created */ /* 01/16/2017(Tommyk): Modified to work for PmodBLE */ /* */ /******************************************************************************/ #include "xil_cache.h" #include "xparameters.h" #include "PmodBLE.h" //required definitions for sending & receiving data over the host board's UART port #ifdef __MICROBLAZE__ #include "xuartlite.h" typedef XUartLite SysUart; #define SysUart_Send XUartLite_Send #define SysUart_Recv XUartLite_Recv #define SYS_UART_DEVICE_ID XPAR_AXI_UARTLITE_0_DEVICE_ID #define BLE_UART_AXI_CLOCK_FREQ XPAR_CPU_M_AXI_DP_FREQ_HZ #else #include "xuartps.h" typedef XUartPs SysUart; #define SysUart_Send XUartPs_Send #define SysUart_Recv XUartPs_Recv #define SYS_UART_DEVICE_ID XPAR_PS7_UART_1_DEVICE_ID #define BLE_UART_AXI_CLOCK_FREQ 100000000 #endif PmodBLE myDevice; SysUart myUart; void DemoInitialize(); void DemoRun(); void SysUartInit(); void EnableCaches(); void DisableCaches(); int main() { DemoInitialize(); DemoRun(); DisableCaches(); return XST_SUCCESS; } void DemoInitialize() { EnableCaches(); SysUartInit(); BLE_Begin ( &myDevice, XPAR_PMODBLE_0_S_AXI_GPIO_BASEADDR, XPAR_PMODBLE_0_S_AXI_UART_BASEADDR, BLE_UART_AXI_CLOCK_FREQ, 115200 ); } void DemoRun() { u8 buf[1]; int n; xil_printf("Initialized PmodBLE Demo, received data will be echoed here, type to send data\r\n"); while(1) { //echo all characters received from both BLE and terminal to terminal //forward all characters received from terminal to BLE n = SysUart_Recv(&myUart, buf, 1); if (n != 0) { SysUart_Send(&myUart, buf, 1); BLE_SendData(&myDevice, buf, 1); } n = BLE_RecvData(&myDevice, buf, 1); if (n != 0) { SysUart_Send(&myUart, buf, 1); } } } //initialize the system uart device, AXI uartlite for microblaze, uartps for Zynq void SysUartInit() { #ifdef __MICROBLAZE__ XUartLite_Initialize(&myUart, SYS_UART_DEVICE_ID); #else XUartPs_Config *myUartCfgPtr; myUartCfgPtr = XUartPs_LookupConfig(SYS_UART_DEVICE_ID); XUartPs_CfgInitialize(&myUart, myUartCfgPtr, myUartCfgPtr->BaseAddress); #endif } void EnableCaches() { #ifdef __MICROBLAZE__ #ifdef XPAR_MICROBLAZE_USE_ICACHE Xil_ICacheEnable(); #endif #ifdef XPAR_MICROBLAZE_USE_DCACHE Xil_DCacheEnable(); #endif #endif } void DisableCaches() { #ifdef __MICROBLAZE__ #ifdef XPAR_MICROBLAZE_USE_DCACHE Xil_DCacheDisable(); #endif #ifdef XPAR_MICROBLAZE_USE_ICACHE Xil_ICacheDisable(); #endif #endif }
Building and uploading the program was simple. Verifying that it was operating correctly took a bit longer.
My normal method of verifying a BLE UART involves using one of the Nordic apps. I've successfully used nRF Connect for Desktop on my PC plus nRF Connect and nRF UART on my Android and iOS tablets. This time I had difficulty getting them to work. nRF Connect would connect on both the PC and tablet, but I couldn't get the send and receive services to work. When testing, I also monitor the debug UART output in a GtkTerm on my Ubuntu Virtual Machine.
nRF Connect for Desktop Bluetooth Low Energy app - connects but cannot send/receive data
nRF Connect on Android - connects but cannot send/receive data
Then I tried the nRF UART app on Android and it would not recognize the PmodBLE as a UART and would disconnect immediately after connecting.
I noticed in the Microchip documentation that there was an MHCP Transparent UART Android app, but that was a few years ago and it has apparently been replaced by the Microchip Bluetooth Data app. This app almost worked, but it only recognized the Receive(Write) service on the Arty.
Microchip Bluetooth Data - has functions in addition to the BLE UART
BLE UART supports multiple chipsets
Only the receive service for the Transparent UART is shown
But it works, Arty receives the data
So, at this point I'm confused. Are all these various apps not working or is there something wrong with the program I'm running on the Arty? I decide to try another program that I've seen mentioned as working with the Microchip Transparent UART -
Serial Bluetooth Terminal by Kai Morich.
Surprise. It works! I can send to and receive from the Arty.
I don't have the access to look under the hood of these apps or modify them, but it could just be an issue recognizing service UUIDs. Why would Microchip's app have a problem? Wish I could have tried the original MHCP Transparent UART app.
So, I have evidence that BLE is working. Now I need to go back and figure out the issue with running with the other Pmods so that I can finish this challenge.