This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Download firmware over BLE for another MCU

Hi,

I've a custom board which has NRF51822 SOC and STM32 SOC. These two are connected over UART. In past I've successfully performed DFU OTA (BLE) for nrf51822 MCU, and now I'd like to use the nrf51 to download firmware over BLE for this other SOC, which is connected over UART. In nutshell, I'd like to

  1. Download firmware image (firmware for another SOC in plain binary format) over BLE using nrf51.
  2. Transfer the firmware image to it's intended host (STM32)

What is the most simplest method to achieve this ? I understand that, in order to send and receive large file (bigger than the maximum payload), I would need to do some segmentation at the sender side (central) and reassembly at the receive side (peripheral). Is there a sample example on such large file transfer? The sample bootloader example provided by Nordic could be a starting point, but at the moment, it seems like an overkill for this particular requirement. I'm looking for something more simpler. Ideally, I'd like to just use some custom service and Bluetooth characteristic to transfer the binary image. Also, At the application/central side, I'd like to use Nordic's Master Control Panel for Android phone or something similar.

Please advice.

Update: 22.07.2016

For the time being, I need to use the same Nordic MCP app for android to achieve OTA for the other MCU that I have on my custom board. Recall that the target MCU is connected to NRF51 over UART interface. As I'm using the same MCP app, I made some changes in my bluetooth application on the periperhal side for NRF51822 and also in the Nordic provided Bootloader for the peripheral. No changes are done in Nordic MCP application.

My current problem is, how do I capture the data packet and send it to STM over UART. The format that I use for control and data transfer between NRF51 and STM over UART is as follows:

Sample control instruction format to STM:

$NRF,CONTROL_CMD,*8-bit XOR checksum of entire packet

$NRF,1,*57 <-- telling STM application to switch to bootloader mode

Similarly I plan to achieve a data packet, something like this:

$NRF,DATA_CMD,DATA_LEN,*8-bit XOR checksum of entire packet

$NRF,2,20,blahblahblahblahblah,*57

The receiver (STM bootloader) will parse these messages. Seeing a data instruction (represented by 2 here), STM will find the length of data (20) and hence will create a buffer of 20 bytes and will program the internal main flash memory of STM. It will then return fail or pass status back to Nordic bootloader. Note that the STM bootloader is seperate piece of code that I wrote and occupies a part of the main flash memory of STM.

dfu_dual_bank.c::dfu_data_pkt_handle() seem like a correct place to capture the data.

case DFU_STATE_RX_DATA_PKT:
     data_length = p_packet->params.data_packet.packet_length * sizeof(uint32_t);
     uint32_t *p_data = (uint32_t *)p_packet->params.data_packet.p_data_packet;

So, I have both the data buffer and the packet size, but how do I copy data from this 32 bit data stream and create a buffer filled with $NRF,2,20,[payload]*[cksum]. The following does not work :(

enum {
    DATA = 3,
    NOK,
};

char buff[256];
char *p;
// clear the buffer
strcpy(buff, "");

sprintf(buff, "$NRF,%d,%d,", DATA, data_length);

// searching for last occurance of ','
p = strrchr(buff, ',');

// advance one position, after the ',' character
p++;
// fill the buffer with the data.
// XXX: p_data is 32 bit pointer, will this work ?
memcpy(p, (char *)p_data, data_length);

// append '*'
*(p + data_length) = '*';

// Terminate with '\0' to use string library function (strlen) later 
*(p + data_length + 1) = '\0';

char checksum = 0;

// 8 bit xor
for (int i = 0; i < strlen(buff); ++i)
{
    checksum ^= buff[i];·
}
char cksum[10];
sprintf(cksum, "%d", checksum);

// concatenate the checksum
strcat(buff, cksum);
// At this point, send the entire frame over UART

With this approach, on the sender (NRF51) side, I see (listening on the Tx pin of Nrf by using a serial terminal program and serial wire):

$NRF,3,20,99

Something went wrong; the terminating * is missing (before 99) and there is no data (after 20 and comma, it should be filled with data)

Update: 25.07.2016

Made some changes for serial communication between the two MCUs (Nordic and STM) and I'm now able to capture more data packets, however I'm still NOT able to capture the entire firmware. In routine dfu_transport_ble.c::app_data_process(), we have:

uint32_t length = p_evt->evt.ble_dfu_pkt_write.len;
uint8_t * p_data_packet = p_evt->evt.ble_dfu_pkt_write.p_data;

So, all I do now,

strcpy(uart_send_buff, "");
sprintf(uart_send_buff, "$NRF,3,%d,", length);
p = strrchr(uart_send_buff, ',');   
p++; // advance one position, after the ',' character
memcpy(p, p_data_packet, length); // copy data packet
// send data packet - uart_put(uart_send_buff);

With the above packet formation for serial transfer, I see the following on serial console (Note that the display mode is Ascii, so I guess that there might be some characters that the serial console could not display. The data length shows that the packet received over BLE was of 20 bytes in length (verified in BLE sniffer capture as well), but as you can see below, most of the packet contents here seem to be empty. I think, i'm making some mistake in packet formation for serial transfer. Your suggestions would be very helpful to debug this further.

$NRF,3,20,^M
$NRF,3,20,^M
$NRF,3,20,^M
$NRF,3,20,<95>«^M
$NRF,3,20,^EQ^M
$NRF,3,20,^EQ^M
$NRF,3,20,^EQ^M
$NRF,3,20,^EQ^M
$NRF,3,20,^EQ^M
$NRF,3,20,ù³^M
$NRF,3,20,^M
$NRF,3,20,^Ah»»»^N^KJ<91>B^EÑ^KH^KI^A`^KH^LI^M
$NRF,3,20,^A`^LH<80>G^LH^M
$NRF,3,20,þç^M
$NRF,3,20,^A^M
$NRF,3,20,0µ^KF^AF^M
$NRF,3,20,^EÓ^]F<95>@I^[%F<95>@@^Y^UFR^^^M
$NRF,3,20,ñÜ0½pµ^M

Final Update: 28.07.2016

Finally, I was able to perform OTA over BLE for the other MCU (This MCU is connected to NRF51 over UART, so I send the firmware image over BLE to NRF51, which sends each chunk of firmware image over UART to the targeted MCU) that I have on my custom board. I implemented a simple flow control mechanism and made improvements in packet parsing at the receiver end and life is good once again :)

  • I think you have all of the right ideas here to implement what you want. I did a very similar thing to bootload a PIC24 OTA through a nRF51822 on a project. What I did was basically:

    1. I had a vendor specific service for my application

    2. I had a characteristic that was written by the central device to send proprietary commands

    3. The central device would send a command that instructed the nRF51 that it wanted to upgrade the PIC24 FW. The nRF51 forwarded that to the PIC24 which went into its bootloader mode. The nRF51 also remembered that that the PIC24 was in bootloader mode

    4. The central device would send the new PIC24 binary down in 20 byte packets which were sent over the UART to the PIC24. The PIC24 would save the binary data to an external EEPROM

    5. When the binary copy was complete the central would send a command to make the PIC24 bootloader validate the CRC of the binary.

    6. If the response to that command was success, the central instructs the PIC24 via the nRF51 to erase its application program and copy in the new binary image.

    7. When the succeeds the central sends a command to reset the PIC24 and resume normal communication operations.

  • Been busy doing some other stuff. I'll try a similar approach. Thank you for sharing your ideas.

  • @jldewitt, today I started working on this feature. So far, I've only worked on the peripheral side and from what you have mentioned in step 4 above, it seems that I would need to do some work on the central side as well. Will I be able to use the Nordic Android application, Master control Panel (MCP) for testing purposes or would have to develop a custom central application /

    Thank you for your help.

  • Yes, you are correct. We were lucky the MCU vendor provided a example bootloader that we were able to put to use. We used their command set over a proprietary service and characteristics to mimic how they would bootload their MCU over a serial port or USB connection. Our app developers had to create the support for these commands in our custom app running on a iOS or Android device. I was able to save them the trouble of converting the hex data to binary by doing that conversion as part of our FW build process.

  • Thank you for swift response. I'm also looking at the nordic bootloader example for the peripheral side implementation. Using a hex file instead of a binary would require additional parsing either at the central or at the peripheral. Luckily ARM buildtool already provides the conversion (ARM binary .axf to plain binary, .bin) utility called nrftool. I had use this same utility while developing a bootloader that would allow over the air update of STM32 SOC firmware over GSM/GPRS network.

Related