Helpful ReplyHot!EZBL over RS-485

Author
bblessing
Super Member
  • Total Posts : 692
  • Reward points : 0
  • Joined: 2008/12/04 06:44:21
  • Location: Cincinnati, OH
  • Status: offline
2018/08/21 13:19:31 (permalink)
0

EZBL over RS-485

I don't have a specific problem, but was able to get EZBL to work over RS-485 with a few quick fixes. First I copied over _UxTXInterrupt from uart1_fifo.c to my Hardware Initializer file, tossed the weak attribute, and made the changes below. Obviously RB13 is the transmit enable line, which is tied to both transmit and receive enable. Next, I changed the following line in main for a much longer boot task: NOW_SetNextTaskTime(&EZBL_bootTask, NOW_ms*128u). Yes this does slow things down a bit, but I can handle 19 seconds total time. This was done with a dsPIC33EP64GS504. I have achieved similar results with a PIC24FJ256GA106 and PIC24FJ256GA108.
 
I would point out that this is still experimental and does fail if I attempt to program it when the application is running. However, another attempt will work. If anyone has a better method, I'd be happy to adopt it :-). For now, though, I hope that this helps somebody out.
 

void __attribute__((interrupt, no_auto_psv)) _U1TXInterrupt(void)
{
    _U1TXIF = 0;

    // Transmit a byte, if possible, if pending
    // NOTE: The FIFO internal data structures are being accessed directly
    // here rather than calling the TX_FIFO_Read*() functions because
    // any function call in an ISR will trigger a whole lot of compiler
    // context saving overhead. The compiler has no way of knowing what
    // registers any given function will clobber, so it has to save them
    // all. For efficiency, the needed read-one-byte code is duplicated here.
    while(!U1STAbits.UTXBF)
    {
        if(UART1_TxFifo.dataCount == 0u)
            break;

        _LATB13 = 1;
        // Transfer a byte from software FIFO to hardware TX FIFO
        U1TXREG = *UART1_TxFifo.tailPtr++;
        if(UART1_TxFifo.tailPtr >= UART1_TxFifo.fifoRAM + UART1_TxFifo.fifoSize)
            UART1_TxFifo.tailPtr = UART1_TxFifo.fifoRAM;
        EZBL_ATOMIC_SUB(UART1_TxFifo.dataCount, 1);
        UART1_TxFifo.activity.tx = 1;
    }
    while (!U1STAbits.TRMT);
    _LATB13 = 0;
}

#1
HowardSchlunder
MCU16 Applications
  • Total Posts : 744
  • Reward points : 0
  • Joined: 2007/06/14 16:26:19
  • Location: Chandler, AZ
  • Status: offline
Re: EZBL over RS-485 2018/08/21 15:36:10 (permalink) ☄ Helpfulby bblessing 2018/08/22 11:06:58
5 (3)
For half-duplex mediums, you might want to change the EZBL_FLOW_THRESHOLD value, for example, at global/file-scope, add:
    EZBL_SetSYM(EZBL_FLOW_THRESHOLD, 96);
The default was 18 bytes in EZBL v2.04 and is 32 bytes in EZBL v2.10.
 
The net effect of making this change will be that the bootloading logic will generate a lot less outbound software flow control messages and better throughput could be achieved. Each message is a 16-bit integer advertising how many bytes of free space are currently available in the software RX FIFO, less any free space previously advertised, but not yet delivered to the RX FIFO (or recognized by software, even though the data may actually be already sitting in the FIFO due to background ISR processing).
 
 
For the best performance and a solution that doesn't depend on the bootloader task execution frequency, I recommend implementing a custom, blocking TX_FIFO_OnWrite() callback function and delete or disable the _U1TXInterrupt() ISR. In your UART1_TX_FIFO_OnWrite() callback, you would:
1. Wait for all RX activity or potential RX activity to cease
2. Set your TX Enable line
3. Copy reqWriteLen bytes of data from *writeSrc to U1TXREG
4. Purge the existing data from destFIFO by calling EZBL_FIFORead((void*)0, destFIFO, bytesPushed);
5. Poll for hardware transmit completion
6. Clear the TX Enable and revert to RX mode
7. Return reqWriteLen
 
Implementing step 1 might entail polling until:
U1STAHbits.RIDLE && ((UART1_RxFifo.dataCount >= EZBL_bootCtx.bytesRequested) || (NOW_32() - startTime > NOW_ms*2u))
where startTime is set to NOW_32() before the test and continuously during the polling loop whenever (!U1STAHbits.RIDLE). The idea is to timeout after the greater of several character idle times or a couple milliseconds to ensure the medium is idle and the remote host node won't transmit anything else. A fixed couple milliseconds is helpful since things like USB to UART transceivers will operate at the mercy of the USB bus, which typically implements a 1ms polling interval for Full Speed USB devices and adds a relatively fixed round trip communications latency. 
 
In normal operation dataCount should match bytesRequested when the PC node stops transmitting, but the timeout is still necessary since the end of file activities involve advertising buffer free space, even though the host node doesn't have any .bl2 file data left to transmit to the Bootloader.
 
 
The _U1TXInterrupt() code can be left in place but disabled by setting the interrupt priority to 0. Statically you could use:
EZBL_SetSYM(UART1_TX_ISR_PRIORITY, 0);
At run-time you could write directly to the IPCx registers to control this, or in EZBL v2.10, via the EZBL_FIFOSetIntPri(&UART1_TxFifo, 0); API. Of course, deleting all code that sets the _U1TXIE bit will also work, but finding this code could be error prone since it could theoretically be written to indirectly via calls to EZBL_FIFOIntEnable(), EZBL_FIFOIntEnableSet(), UART1_FIFO_EnableInterrupts(), EZBL_SetIntEn(), EZBL_WrIntEn(), EZBL_InvIntEn(), UART1_TX_FIFO_OnWrite(), etc., even though the current releases of EZBL don't actually call all of these.
 
 
post edited by HowardSchlunder - 2018/08/21 15:37:37
#2
bblessing
Super Member
  • Total Posts : 692
  • Reward points : 0
  • Joined: 2008/12/04 06:44:21
  • Location: Cincinnati, OH
  • Status: offline
Re: EZBL over RS-485 2018/08/21 17:25:26 (permalink)
0
I'll test that out as soon as I can! Thank you!

I have to admit that working with EZBL has been a humbling experience. Out of the box it worked great for a project utilizing an FTDI USB/UART chip. Digging into the guts of the project has shown me techniques that I've never seen in practice. Hopefully I'll be able to step up my game.

If you were instrumental in writing EZBL, which wouldn't be a surprise as your name was all over the source code for the old MLA TCP/IP stack, then my hat goes off to you. It truly is something to behold.
#3
HowardSchlunder
MCU16 Applications
  • Total Posts : 744
  • Reward points : 0
  • Joined: 2007/06/14 16:26:19
  • Location: Chandler, AZ
  • Status: offline
Re: EZBL over RS-485 2018/08/22 15:09:13 (permalink) ☄ Helpfulby bblessing 2018/08/24 10:48:36
5 (3)
Yes, I might have had some involvement writing EZBL. However, bootloaders can downgrade expensive hardware into bricks or enable Internet hackers to reprogram your ECU as you drive down the freeway, so I uhh, prefer to think that some "applications engineering team at Microchip" was primarily responsible for EZBL's development.
 
I tested my prior suggestion on an Explorer 16/32 + PIC24FJ1024GB610 PIM @ 460800 baud and monitored a GPIO (TX_EN) pin + U2RX and U2TX using a logic analyzer. I observed successful bootloading and half-duplex communications that should be compatible with an RS-485 or RS-422 network using the following code. This example can be simply added to ex_boot_uart\main.c under EZBL v2.10 without digging into the UART code in ezbl_lib.a or rewriting the transmit ISR (although the ISR does become a minor amount of dead code by ignoring it).
 
The only adjustment I needed compared to my prior description was some compensation while reading EZBL_bootCtx.bytesRequested. EZBL_Install2Flash() adds the free-space flow control advertisements to this variable just before transmitting said flow control advertisements. This makes the RX Idle test always end by the slower timeout fallback if the variable is used without un-adding the advertisement first.
 
EZBL_SetSYM(EZBL_FLOW_THRESHOLD, 96);
EZBL_SetSYM(UART2_TX_ISR_PRIORITY, 0);

unsigned int UART2_TX_FIFO_OnWrite(unsigned int bytesPushed, void *writeSrc, unsigned int reqWriteLen, EZBL_FIFO *destFIFO)
{
unsigned short expectedRXCount;
destFIFO->activity.softTx = 1;

if(reqWriteLen == 0)
return 0;

// Delete data in software TX FIFO - we will bypass the buffer and do a blocking/polled TX instead
EZBL_FIFORead(0, destFIFO, bytesPushed);

// Determine how many RX bytes should exist when remote node will go silent
expectedRXCount = EZBL_bootCtx.bytesRequested;
if(reqWriteLen == 2u) // EZBL_Install2Flash() pre-adds EZBL_bootCtx.bytesRequested by free space TX messages, so undo this offset
{
expectedRXCount -= (((unsigned short)((unsigned char*)writeSrc)[1])<<8) | ((unsigned short)((unsigned char*)writeSrc)[0]);
if(expectedRXCount > EZBL_bootCtx.bytesRequested)
expectedRXCount = EZBL_bootCtx.bytesRequested;
}

// Wait for RX idle
do
{
unsigned long startTime = NOW_32();
while((UART2_RxFifo.dataCount < expectedRXCount) && (NOW_32() - startTime < NOW_ms*2u));
} while(!U2STAbits.RIDLE);

// Copy write data to hardware TX FIFO
LEDOn(0x02); // Set TX Enable control
for(bytesPushed = 0; bytesPushed < reqWriteLen; bytesPushed++)
{
while(U2STAbits.UTXBF);
U2TXREG = (unsigned int)((unsigned char*)writeSrc)[bytesPushed];
}
while(!U2STAbits.TRMT); // Wait for hardware FIFOed data to finish transmitting
LEDOff(0x02); // Clear TX Enable and restore RX mode

return reqWriteLen;
}

#4
bblessing
Super Member
  • Total Posts : 692
  • Reward points : 0
  • Joined: 2008/12/04 06:44:21
  • Location: Cincinnati, OH
  • Status: offline
Re: EZBL over RS-485 2018/08/24 10:50:12 (permalink)
0
Sorry for the late reply, as I have been away from any hardware for the past couple of days. It didn't take long to show just how much better your method is: 2.175s vs. 19s to program. Thank you again for this!
#5
SergioP
New Member
  • Total Posts : 1
  • Reward points : 0
  • Joined: 2018/09/10 05:34:19
  • Location: 0
  • Status: offline
Re: EZBL over RS-485 2018/09/11 01:01:32 (permalink)
0
Hello,
First of all, thank you very much for your contributions. They are awesome.
 
I want to share my own experience with Howard´s code:
I have an rs485 setting and I was getting an error until I deleted the compensation while reading EZBL_bootCtx.bytesRequested. After that I successfully loaded a program.
 
Howard, do you know what could be happening? You would be very kind solving this mystery ;)
 
Here is part of the "Log" automatically saved by MPLAB:
 

 0.165855: RX  2 @ 40:
    13 FF                                              ..             
 0.197849: RX  2 @ 42:
    13 FF                                              ..             
 0.197857: RX  2 @ 44:
    11 FF                                              ..             
 0.197862: RX  2 @ 46:
    60 00                                              `.             
 0.198059: TX 96 @ 64:
    80 01 00 00 00 00 00 00 4A 02 04 00 00 00 20 1D    ........J..... .
    00 10 1C 00 14 1C 00 18 1C 00 1C 1C 00 20 1C 00    ............. ..
    20 1D 00 20 1D 00 24 1C 00 28 1C 00 2C 1C 00 30     .. ..$..(..,..0
    1C 00 34 1C 00 38 1C 00 3C 1C 00 2C 02 00 44 1C    ..4..8..<..,..D.
    00 48 1C 00 4C 1C 00 50 1C 00 54 1C 00 58 1C 00    .H..L..P..T..X..
    5C 1C 00 20 1D 00 60 1C 00 64 1C 00 20 1D 00 68    \.. ..`..d.. ..h
 0.223375: COM read error: bytesLeft = 2, chunkSize = 2, ret = 0, *writePtr = 0x00, flags = 0x00000008
    comStat = {cbInQue = 0, cbOutQue = 0, fCtsHold = 0, fDsrHold = 0, fEof = 0, fRlsdHold = 0, fTxim = 0, fXoffHold = 0, fXoffSent = 0}
    Retrying read call
 0.243951: RX  1 @ 48:
    80                                                 .              
 2.173454: RX  1 @ 49:
    00                                                 .              
 2.173713: TX 128 @ 160:
    1C 00 6C 1C 00 70 1C 00 74 1C 00 78 1C 00 7C 1C    ..l..p..t..x..|.
    00 80 1C 00 84 1C 00 88 1C 00 8C 1C 00 90 1C 00    ................
    36 02 00 40 02 00 9C 1C 00 A0 1C 00 A4 1C 00 A8    6..@............
    1C 00 AC 1C 00 B0 1C 00 B4 1C 00 B8 1C 00 BC 1C    ................
    00 C0 1C 00 C4 1C 00 C8 1C 00 CC 1C 00 20 1D 00    ............. ..
    D0 1C 00 D4 1C 00 D8 1C 00 DC 1C 00 E0 1C 00 E4    ................
    1C 00 E8 1C 00 EC 1C 00 F0 1C 00 F4 1C 00 F8 1C    ................
    00 20 1D 00 20 1D 00 FC 1C 00 00 1D 00 04 1D 00    . .. ...........
 2.176581: RX  2 @ 50:
    00 EC                                              ..             
 2.180340: RX  1 @ 52:
    FF                                                 .              
 4.382221: Timeout reading from 'COM3'
 
 
 
By the way, configuring the UART with UEN =2  makes unnecessary to manually set and clear the TX Enable line (Or, at least, it works with my configuration)
#6
HowardSchlunder
MCU16 Applications
  • Total Posts : 744
  • Reward points : 0
  • Joined: 2007/06/14 16:26:19
  • Location: Chandler, AZ
  • Status: offline
Re: EZBL over RS-485 2018/09/19 14:51:07 (permalink)
0
Hello SergioP,
 
The COM read error at time = 0.223375s is a PC-side ezbl_comm.exe fread() call failure against the PC's "\\.\COM3" communications resource path.
 
The Bootloader only transmits 16-bit flow control messages or the 16-bit 0x0000 termination code, followed by a 16-bit status/error code. Right when the PC COM read error occurred, a normal 16-bit flow control message was expected. The 0x00 RX bytes @ offset 49 and 50 are a 0x0000 termination message, and the 0xEC and 0xFF RX bytes @ offset 51 and 52 are the EZBL_ERROR_COM_READ_TIMEOUT error code. The singular 0x80 RX byte @ 48 is not something your EZBL Bootloader ever generated and transmitted (apparent since you have the default 96 byte RX FIFO defined in your Bootloader, which is always the first flow control advertisement after the bootloader has finished erasing or blank checking the existing App flash regions).
 
My conclusion is that you have severe errors occurring on the wire of your communications medium. The PC has lost one or more RX bytes and corrupted 1 or more bits to see the 0x80 orphaned byte, and simultaneously, the Bootloader has lost numerous RX bytes from the PC's transmissions @ 64 and @ 160 in order to timeout expecting more data to arrive. These conditions all point to bus contention on a half-duplex medium. Both nodes are blindly jabbering away, not willing or able to listen to the other node before opening its own mouth and correspondingly hearing truncated garbage when they finish talking and revert to RX mode again.
 
Whatever compensation code you deleted needs to be reinstated. It serves an essential function and is required for compatibility with a half-duplex medium. Without it, the bootloader will transmit when it must instead remain listening. RS-485 does not have hardware carrier sense, so software must implement a stateful algorithm to know when the remote node is able to listen.
 
Since you indicated some kind of failure with the compensation code, you may need to modify it in some way to make it more pessimistic, such as by adding an additional, fixed RX to TX turnaround delay after the expected medium silence. I don't know what kind of RS-485 transceiver you have connected to your PC, but it may require one or two USB polling intervals to elapse before it switches from TX mode back to RX mode. I.e. try adding > 2ms of bootloader pre-TX holdoff in addition to the EZBL_bootCtx.bytesRequested tracking code.
#7
Jim Nickerson
User 452
  • Total Posts : 5458
  • Reward points : 0
  • Joined: 2003/11/07 12:35:10
  • Location: San Diego, CA
  • Status: offline
Re: EZBL over RS-485 2018/09/20 06:59:47 (permalink)
0
As Howard states you require enough time for the 485 to switch from Tx to Rx.
I have also found adding "Passive Failsafe bias resistors" help in limiting the false characters when switching from Tx to Rx and the bus is idle as described in this pdf for example http://www.ti.com/lit/an/slyt324/slyt324.pdf
#8
HaiJiao
New Member
  • Total Posts : 6
  • Reward points : 0
  • Joined: 2018/07/15 23:07:08
  • Location: 0
  • Status: offline
Re: EZBL over RS-485 2018/11/08 01:13:38 (permalink)
0
我现在就在搞这个     RS485 下载   2.04版本   可是 下载不进去    拜托了。
#9
qhb
Superb Member
  • Total Posts : 7543
  • Reward points : 0
  • Joined: 2016/06/05 14:55:32
  • Location: One step ahead...
  • Status: online
Re: EZBL over RS-485 2018/11/08 01:41:09 (permalink)
5 (1)
HaiJiao
我现在就在搞这个     RS485 下载   2.04版本   可是 下载不进去    拜托了。

Google translate

I am working on this RS485 download 2.04 version now, but the download does not go in. Please.

Please, you have already been asked once before to START YOUR OWN TOPIC.
Also, you are much more likely to get help on this forum if you post in English.
#10
HaiJiao
New Member
  • Total Posts : 6
  • Reward points : 0
  • Joined: 2018/07/15 23:07:08
  • Location: 0
  • Status: offline
Re: EZBL over RS-485 2018/11/13 19:32:03 (permalink)
0
 
This's  Mine  PIC24FJ128GA310 information  
But   Mine  dsPIC33ep128GM310 OK   Without this “EZBL_SetSYM(EZBL_FLOW_THRESHOLD, 96);”
Upload progress: |0% 25% 50% 75% 100%|
|..................................................
EZBL communications error: remote node aborted with error -26 around file offset 126140 (of 126140)
Bootloader computed CRC mismatch with CRC contained in firmware image. Probable communications error.
Log saved to: C:\Users\haiji\AppData\Local\Temp\ezbl_comm_log.txt
 
 
 
 
 
 
 
 
 
 
/**
* EZBL Bootloader "main" file for initializing communications hardware,
* checking app-installed flags, receiving new application firmware, and
* dispatching execution to the Application's reset/main() routines.
*
* Interrupt Service Routines implemented in this project are:
* - One 16-bit Timer or CCT Interrupt, selected in the hardware initializer file (ISR implementation defined in ezbl_lib.a, see ezbl_lib -> weak_defaults/_TxInterrupt.s (or _CCTxInterrupt.s))
* - UART 2 RX (defined in ezbl_lib.a, see ezbl_lib -> weak_defaults/uart2_fifo.c; can be a different UART instance, see UART_Reset() in hardware initializer)
* - UART 2 TX (defined in ezbl_lib.a, see ezbl_lib -> weak_defaults/uart2_fifo.c; can be a different UART instance, see UART_Reset() in hardware initializer)
*/
// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (C) 2017 Microchip Technology Inc.
MICROCHIP SOFTWARE NOTICE AND DISCLAIMER: You may use this software, and any
derivatives created by any person or entity by or on your behalf, exclusively
with Microchip's products. Microchip and its licensors retain all ownership
and intellectual property rights in the accompanying software and in all
derivatives here to.
This software and any accompanying information is for suggestion only. It
does not modify Microchip's standard warranty for its products. You agree
that you are solely responsible for testing the software and determining its
suitability. Microchip has no obligation to modify, test, certify, or
support the software.
THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR
PURPOSE APPLY TO THIS SOFTWARE, ITS INTERACTION WITH MICROCHIP'S PRODUCTS,
COMBINATION WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
IN NO EVENT, WILL MICROCHIP BE LIABLE, WHETHER IN CONTRACT, WARRANTY, TORT
(INCLUDING NEGLIGENCE OR BREACH OF STATUTORY DUTY), STRICT LIABILITY,
INDEMNITY, CONTRIBUTION, OR OTHERWISE, FOR ANY INDIRECT, SPECIAL, PUNITIVE,
EXEMPLARY, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, FOR COST OR EXPENSE OF
ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWSOEVER CAUSED, EVEN IF
MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.
TO THE FULLEST EXTENT ALLOWABLE BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL
CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF
FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
TERMS.
*******************************************************************************/
// DOM-IGNORE-END
#include <xc.h>
#include <stdlib.h>
#include <libpic30.h>
#include <string.h>
#include <stdarg.h>
#include "ezbl_integration/ezbl.h"

// EZBL ezbl_lib.a link-time options:
//EZBL_SetSYM(EZBL_NO_APP_DOWNGRADE, 1); // Uncomment to disallow upload of App image with a version/build number that is < existing App version (assuming a valid App exists). Note: This can be circumvented if someone starts uploading a recent App image, they interrupt power or communications, then upload older firmware. With nowhere to store an offered Application but in an erased flash, the act of starting a valid upload results in prior knowledge of which older version(s) are disallowed.
//EZBL_SetSYM(EZBL_FLOW_THRESHOLD, 48); // Optional water mark to adjust when outbound flow control advertisements are generated. Small values consume more TX bandwidth by generating more messages. See EZBL_Install2Flash() API documentation for additional information.
//EZBL_SetSYM(UART2_TX_ISR_PRIORITY, 1); // Optionally change the U2TX Interrupt priority. The default is IPL 1 (lowest possible priority).
//EZBL_SetSYM(UART2_RX_ISR_PRIORITY, 2); // Optionally change the U2RX Interrupt priority. The default is IPL 2 (low priority).

// General Bootloader timeout governing reset idle time to initial Application
// launch and bootload termination when communications are broken.
#define BOOTLOADER_TIMEOUT (NOW_sec * 1u)

// Uncomment for superior performance (with baud rates up to 761kbps). Buffer
// default size is 96 bytes in ezbl_lib, which conserves static RAM, but reduces
// sustained throughput. Any size >= 64 bytes can be used for bootloading.
//unsigned char UART2_RxFifoBuffer[1024] __attribute__((section(".bss.UART2_RxFifoBuffer")));

// Bootloader global variables and flags
NOW_TASK EZBL_bootloaderTask __attribute__((persistent)); // Task callback pointers/timers to background execute the EZBL_BootloaderTask() function
EZBL_INSTALL_CTX EZBL_bootCtx __attribute__((persistent)); // State tracking structure, including timeout detection for active bootload operations
int (*EZBL_AppPreInstall)(EZBL_FIFO *rxFromRemote, EZBL_FIFO *txToRemote, unsigned long fileSize, EZBL_APPID_VER *appIDVer) = 0; // Application's EZBL_PreInstall() callback function pointer to permit current App rejection of offered firmware or clean App shutdown
 
int main(void)
{
unsigned long appLaunchTimer; // Timestamp tracking when we last saw COM/Bootloader activity
unsigned long ledTimer; // Timestamp tracking when we last toggled an LED
unsigned long now; // Cached return value from NOW_32()

EZBL_SetSYM(EZBL_FLOW_THRESHOLD, 96);
EZBL_SetSYM(UART1_TX_ISR_PRIORITY, 0);//close uart1 interrupt
// Initialize Bootloader global variables and flags. Explicit zeroing is
// necessary if this Bootloader project is built with "--no-data-init"
// xc16-ld Linker option used (i.e. "Initialize data sections" unchecked to
// save code space). For default (initialization enabled) state, this code
// could be removed.
EZBL_ForwardBootloaderISR = 0x00000000;
EZBL_appIsRunning = 0;
EZBL_NVMKey = 0x0000;
EZBL_COM_RX = 0;
EZBL_AppPreInstall = 0;

// Set processor clock, configure LED/Button I/O pin states, PPS
// assignment, initialize NOW timer peripheral, UART/I2C communications, etc.
InitializeBoard();
// Launch Bootloader communications listener and command processor periodic
// task (background calls EZBL_BootloaderTask() from IPL0/main() context
// every ~32ms). EZBL_Install2Flash() API start requirements require that we
// first initialize EZBL_bootCtx state.
EZBL_bootCtx.state = SM_SYNC_INIT;

TRISAbits.TRISA7=1;
TRISGbits.TRISG0=1;

if(PORTGbits.RG0==0 && PORTAbits.RA7==0) EZBL_bootCtx.timeout=(NOW_sec * 30u);
else EZBL_bootCtx.timeout=(NOW_sec * 30u);

// EZBL_bootCtx.timeout = BOOTLOADER_TIMEOUT;
NOW_CreateRepeatingTask(&EZBL_bootloaderTask, EZBL_BootloaderTask, 32u*NOW_ms);

now = NOW_32();
appLaunchTimer = now;
ledTimer = now;

// Main Bootloader LED blink and App dispatch timeout loop
while(1)
{
ClrWdt();
// Every 62.5ms toggle a heartbeat LED (8 Hz blink rate) indicating this Bootloader is executing
now = NOW_32();
if(now - ledTimer > NOW_sec/16u)
{
ledTimer += NOW_sec/16u;
TRISAbits.TRISA5 =0;
LATAbits.LATA5= ~LATAbits.LATA5;
}
// Check if it is time to jump into the application (default is 1 second
// of nothing being received, as defined by BOOTLOADER_TIMEOUT.
if(EZBL_COMBootIF->activity.any)
{
// Activity happened, so reset launch timer to full interval remaining
EZBL_COMBootIF->activity.any = 0x0000;
appLaunchTimer = now;
}
if(now - appLaunchTimer > EZBL_bootCtx.timeout)
{
// If auto-baud is used, automatically reset the UART back to
// auto-baud mode while idle for longer than the timeout.
if(EZBL_COMBaud <= 0)
{
EZBL_FIFOSetBaud(EZBL_COMBootIF, EZBL_COMBaud); // This will set EZBL_COMBootIF->activity.other, so appLaunchTimer will also be reset on next loop iteration
}
if(EZBL_IsAppPresent())
{
// LEDOff(0xFF); // Executes LEDToggle(0x00FF & LEDToggle(0)); to turn off all LEDs we were blinking

// Optionally turn off all Bootloader ISRs and forward the
// interrupts to the Application so we become a passive classic
// bootloader.
// NOTE: You are giving up useful timing and communications APIs
// if you do this. Also, the automatic bootloader wakeup upon
// .bl2 file presentation won't work. To minimize flash, the
// App can just reuse the bootloader APIs as is, keeping the
// NOW Timer interrupt and communications ISRs active in the
// background (which have minimal run-time execution cost).

EZBL_RAMSet((void*)&IEC0, 0x00, (unsigned int)&IPC0 - (unsigned int)&IEC0); // Clear every bit in all IECx Interrupt Enable registers
EZBL_ForwardBootloaderISR = 0xFFFFFFFF; // Forward all Interrupts to the Application
NOW_EndAllTasks(); // Terminates the EZBL_BootloaderTask() from executing via background NOW ISR and when a NOW_32() or NOW_64() call is made which indirectly needs the timer ISR to execute and perform a carry propagation.
EZBL_StartAppIfPresent(); // Sets EZBL_appIsRunning = 0xFFFF and temporarily disables IPL6 and lower interrupts before launching Application
}
}
// Not much going on in this loop. Let's save power. The NOW Timer ISR
// will wake us up, as will COM RX events.
Idle();
}
}
/**
* Callback function automatically invoked anytime a write is made against the
* UART TX FIFO (with or without any data actually getting written). Writes
* occur when the EZBL_FIFOWrite() function is called (possibly indirectly
* through a wrapper function).
*
* This callback executes after the write has already taken place and is a
* convenient place to trigger necessary hardware actions, spy on the data
* passing through, tee it to another communications or storage interface, or
* implement additional FIFO features, such as a blocking/almost guaranteed
* write with timeout mechanism to simplify other communications code.
*
* If a write is made without enough FIFO space to store all of the data, this
* callback executes after the FIFO has been completely filled and provides an
* opportunity to process the residual data.
*
* The default callback implementation will block when the FIFO is full and
* trigger the UART TX ISR as needed to ensure the data doesn't have to be
* thrown away. However, blocking will abort and throw unbuffered data away
* after a fixed timeout is reached (ex: UART's 'ON' bit is clear, resulting in
* clearance of data from the FIFO) The default timeout is set to 250ms (2,880
* bytes @ 115200 baud, 480 bytes @ 19200), which can be changed in the callback
* code.
*
* @param bytesPushed Number of bytes that actually got written to the software
* FIFO before this callback was invoked.
* @param *writeSrc Pointer to the memory originally used when the FIFO write
* call was made. As no other code has executed yet, ordinary
* RAM data pointers can be re-read here to see or peek at all
* of the requested write data.
* @param regWriteLen Number of bytes that were requested to be written when the
* FIFO write call was made. Generally this will match the
* bytesPushed value unless the TX FIFO is completely full.
* @param *destFIFO Pointer to the EZBL_FIFO that called this callback function.
*
* @return Number of bytes that you want to return back to the EZBL_FIFOWrite()
* caller as reportedly being successfully written. Generally you should
* return bytesPushed unless you've taken some action to transfer more
* data (or perhaps stolen some back out of the FIFO).
*/
 

unsigned int UART1_TX_FIFO_OnWrite(unsigned int bytesPushed, void *writeSrc, unsigned int reqWriteLen, EZBL_FIFO *destFIFO)
{
unsigned short expectedRXCount;
destFIFO->activity.softTx = 1;
if(reqWriteLen == 0)
return 0;
// Delete data in software TX FIFO - we will bypass the buffer and do a blocking/polled TX instead
EZBL_FIFORead(0, destFIFO, bytesPushed);
// Determine how many RX bytes should exist when remote node will go silent
expectedRXCount = EZBL_bootCtx.bytesRequested;
if(reqWriteLen == 2u) // EZBL_Install2Flash() pre-adds EZBL_bootCtx.bytesRequested by free space TX messages, so undo this offset
{
expectedRXCount -= (((unsigned short)((unsigned char*)writeSrc)[1])<<8) | ((unsigned short)((unsigned char*)writeSrc)[0]);
if(expectedRXCount > EZBL_bootCtx.bytesRequested)
expectedRXCount = EZBL_bootCtx.bytesRequested;
}
// Wait for RX idle
do
{
unsigned long startTime = NOW_32();
while((UART1_RxFifo.dataCount < expectedRXCount) && (NOW_32() - startTime < NOW_ms*2u));
} while(!U1STAbits.RIDLE);
// Copy write data to hardware TX FIFO
LATFbits.LATF2 =0; // Set TX Enable control
for(bytesPushed = 0; bytesPushed < reqWriteLen; bytesPushed++)
{
while(U1STAbits.UTXBF);
U1TXREG = (unsigned int)((unsigned char*)writeSrc)[bytesPushed];
}
while(!U1STAbits.TRMT); // Wait for hardware FIFOed data to finish transmitting
LATFbits.LATF2 =1; // Clear TX Enable and restore RX mode
return reqWriteLen;
}
/**
* Periodically called EZBL bootloader task callback function. This function
* executes at IPL 0 (main() context), essentially acting like a virtual
* software ISR created by the NOW_CreateRepeatingTask() call.
*
* NOTE: Unless you disable the NOW interrupt and forward it to the Application,
* this function will continue to execute in the background even while the
* Application is running. This allows the Bootloader to wake up and process an
* offered .bl2 image file at any time. This task can be manually ended by
* calling EZBL_EndTask(&EZBL_bootCtx) from this Bootloader or the Application
* project.
*
* @return 0 - value not used.
*/
int EZBL_BootloaderTask(void)
{
// Do bootloader processing when the communications RX ISR has detected the
// BOOTLOADER_WAKE_KEY sequence (default "MCUPHCME") has been received on
// a FIFO'd communications interface and set the EZBL_COM_RX (and
// EZBL_COM_TX) global pointers to a non-null value.
if(EZBL_COM_RX)
{
// Run the EZBL state machine that reads from the communications port via
// EZBL_COM_RX, responds via EZBL_COM_TX, handles flow control, erases flash
// (only when valid firmware offering presented and EZBL_PreInstall()
// callback returns 1), programs flash, validates with CRC and read-back,
// then programs a App-valid flag to allow new Application execution. For
// the first call, the EZBL_INSTALL_CTX.state, and timeout fields must be
// pre-configured (done during main() initialization):
// EZBL_bootCtx.state = SM_SYNC_INIT;
// EZBL_bootCtx.timeout = BOOTLOADER_TIMEOUT;
EZBL_Install2Flash(&EZBL_bootCtx);
// When Bootloader is communicating, increase task frequency for lower
// communications latency and better throughput. EZBL_Install2Flash() sets
// EZBL_COM_RX to null when a rejection, timeout, error or successful
// bootload completion occurs.
NOW_SetNextTaskTime(&EZBL_bootloaderTask, NOW_ms);
}
if(EZBL_COMBaud <= 0)
{
if(EZBL_COMBootIF->activity.framingError) // On framing errors or Break characters, revert back to auto-baud, even if the Application has already been launched
EZBL_FIFOSetBaud(EZBL_COMBootIF, EZBL_COMBaud); // This will set EZBL_COMBootIF->activity.other = 1 (and clear activity.framingError), so appLaunchTimer will also be reset on next bootloader main() while(1) loop iteration.
}
return 0;
}

// Callback function executed by EZBL_Install2Flash() just before the existing
// Application (if any) is erased, permitting last minute rejection of a
// firmware update or an opportunity to cleanly shut down any running operations
// (especially if they might interfere with successful Bootloading). See
// callback documentation for EZBL_PreInstall() in ezbl.h for more information.
int EZBL_PreInstall(EZBL_FIFO *rxFromRemote, EZBL_FIFO *txToRemote, unsigned long fileSize, EZBL_APPID_VER *appIDVer)
{
if(EZBL_AppPreInstall)
return (*EZBL_AppPreInstall)(rxFromRemote, txToRemote, fileSize, appIDVer);
return 1; // Accepts update offering if no App installed or running right now
}

// These trap handlers are not necessary, but if you ever find your Bootloader
// going out to lunch (and probably crashing a debug session with
// PICkit/ICD/REAL ICE), then be sure to enable these. When absent from the
// bootloader project, EZBL remaps all of the trap vectors to the Application's
// Interrupt Goto Table, which will not help you debug Bootloader problems (and
// confuses the debuggers because there is usually nothing in App flash space at
// the time, resulting in NOPR execution until the end of flash is hit -- which
// triggers another unreachable trap.)
#if defined(__DEBUG)
void __attribute__((interrupt, auto_psv)) _AddressError(void) // Consider EZBL_KeepSYM(_AddressError); for a more powerful trap handler
{
EZBL_printf("\n\nAddress Error Trap!");
EZBL_FIFOFlush(EZBL_STDOUT, NOW_sec);
__builtin_software_breakpoint();
INTCON1 &= 0x8700;
}
void __attribute__((interrupt, auto_psv)) _StackError(void) // Consider EZBL_KeepSYM(_StackError); for a more powerful trap handler
{
EZBL_printf("\n\nStack Error Trap!");
EZBL_FIFOFlush(EZBL_STDOUT, NOW_sec);
__builtin_software_breakpoint();
INTCON1 &= 0x8700;
}
void __attribute__((interrupt, auto_psv)) _MathError(void) // Consider EZBL_KeepSYM(_MathError); for a more powerful trap handler
{
EZBL_printf("\n\nMath Error Trap!");
EZBL_FIFOFlush(EZBL_STDOUT, NOW_sec);
__builtin_software_breakpoint();
INTCON1 &= 0x8700;
}
#endif
#11
HaiJiao
New Member
  • Total Posts : 6
  • Reward points : 0
  • Joined: 2018/07/15 23:07:08
  • Location: 0
  • Status: offline
Re: EZBL over RS-485 2018/11/13 19:39:22 (permalink)
0
my EZBL V2.04
#12
Jump to:
© 2018 APG vNext Commercial Version 4.5