Microchip RN4020 Bluetooth LE

Thread Starter

joeyd999

Joined Jun 6, 2011
6,297
If you find a good "middle" where you can put the check it certainly will work, but then changing your "big thingy" code will move this point back and forth in time and may disturb timing.
In fact, the high-priority routine in question is an A/D converter connected via SPI. I only have a small window in which to change the mux and read the contents of the A/D result register without corrupting the next reading. This requires a good number of SPI transactions. I am at the moment working on checking the RCIF while waiting for each SPI transaction to complete. I won't be able to test till tomorrow.

You can try re-saving your shadow registers and enabling high-priority interrupts before entering your "big thingy" then restoring it all back at the end of it. This way your Bluetooth interrupts can interrupt your "big thingy". If your "big thingy" has critical sections which cannot be interrupted, then you can disable the interrupt around these sections.
This is actually a great idea! I just need to analyze the A/D code to see if it'll be tolerant of random interruptions.

BTW, the receiver interrupt code is pretty tight:

Code:
;****************************************************
;** RC1INT -- Capture recieved byte from Bluetooth **
;**   Hi priority -- use fast return               **
;****************************************************

rc1int    movff    fsr2l,hfsr2l        ;save fsr context
    movff    fsr2h,hfsr2h   

    lfsr    2,rxbuff        ;point to rxbuffer (on 256 byte boundry)
    movff    _rxhead,fsr2l        ;  next byte in queue (modulo 256)

rc1ir    movff    rcreg1,postinc2        ;copy byte into queue & update pointer

    btfsc    rcsta1,oerr        ;overrun error?
    bcf    rcsta1,cren        ;yes, toggle cren
    bsf    rcsta1,cren

    bbs    pir1,rc1if,0,rc1ir    ;repeat if another character in buffer
    movff    fsr2l,_rxhead        ;set new head position

    movff    hfsr2l,fsr2l        ;restore context
    movff    hfsr2h,fsr2h

    retfie    fast            ;fast return
I had to add the OERR check because I learned, only today, that the PIC18 EUSART receiver quits when the OERR flag gets set. I've never run into this before...and I've written lotsa EUSART code over the years.
 

NorthGuy

Joined Jun 28, 2014
611
OERR only gets set if you skip a byte. I usually don't worry about it as I'm making sure I catch all the bytes ;)

If your ADC SPI routine doesn't use FSR2 then you can prepare FSR2 before it (and of course restore FSR2 after). Then checking on the Bluetooth will only take 2 lines (3 cycles) and you can insert it in multiple places across the SPI routine.

Code:
  btfsc PIR1,RC1IF
  movff RCREG1,POSTINC2
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,297
OERR only gets set if you skip a byte. I usually don't worry about it as I'm making sure I catch all the bytes ;)

If your ADC SPI routine doesn't use FSR2 then you can prepare FSR2 before it (and of course restore FSR2 after). Then checking on the Bluetooth will only take 2 lines (3 cycles) and you can insert it in multiple places across the SPI routine.

Code:
  btfsc PIR1,RC1IF
  movff RCREG1,POSTINC2
Yup.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,297
Here's my RN4020 Bluetooth LE code so far (EUSART code excluded). Since my application cannot sit and wait for command responses to come from the module, (there are like 20,000 other things going on) it is set up as a state machine. It turned out to be quite a bit simpler than I expected.

BTINIT is call once. Then, POLLBT is call once for each pass of the main loop. The state machine takes care of parsing standard responses, timed states, time-outs while awaiting responses, and erroneous responses.

So far, this is enough to get the RN4020 initialized, advertising, and connected. In the next couple of days, I'll be adding support for non-standard responses, which is required for processing characteristics to/from the paired device.

This is, in fact, quite fun!

Comments welcome...

Code:
;*************************************
;** BTINIT -- Initialize Bluetooth **
;*************************************

initbt
    BANKSEL    btstate            ;select bluetooth working bank        

    bsf    wakesw            ;wake bluetooth
    bsf    wakehw

    bra    ibtex            ;exit restoring bank


;*****************************************
;** BTPRCV -- Process Bluetooth receiver **
;*****************************************

btprcv    retbc    fbtinit            ;don't receive if in initialzation

    clrf    btsresp,1        ;clear standard response flags

    movlf    fsr1h,high btrcvbuff    ;point to receiver buffer
    movff    btrhead,fsr1l        ;  and index to next character

btplp    rcall    rxbyte            ;receiver byte available?
    retz                ; z if none

    movwf    indf1            ;save character at current position
    movlw    '\r'            ;ignore return characters
    cpfseq    indf1
    movf    postinc1,w        ;get back in w, and update pointer
    movff    fsr1l,btrhead        ;save new head position

    xorlw    '\n'            ;new character a line feed?
    bnz    btplp            ;no, get some more characters, if available

    movlfb    btrhead,low btrcvbuff    ;reset btrhead for next message

;parse for common messages
;if common response not matched, indicate (likely) parameters returned from RN4020

    bsf    btsresp,0,1        ;set 1st bit in standard response flags

    movdf    tblptr,btcmes        ;tblptr -> possible responses (\n separated, \r terminated)

btplp0    lfsr    0,btrcvbuff        ;fsr0 -> point to head of response buffer

btplp1    tblrd    *+            ;get next character from list of responses

    movlw    '\r'            ;\r is response list terminating character
    xorwf    tablat,w        ;  end of response list?
    bz    btpnmf            ;yes, no response matched

    movf    tablat,w        ;get character

    cpfseq    postinc0        ;test against charcter in response buffer
    bra    btpnom            ;!= means no match, skip to next response

    xorlw    '\n'            ;new line character?
    bz    btpmat            ;yes, we have found a match

    bra    btplp1            ;keep testing characters till match

;no match of current response, skip ahead till /n or /r

btpnom    clrc                ;roll to next response
    rlcf    btsresp,f,1

btplp2    tblrd    *+            ;get next character from list of responses

    movlw    '\r'            ;get terminating character
    xorwf    tablat,w        ; end of response list?
    bz    btpnmf            ;yes, no response matched

    movlw    '\n'            ;is it a new line character?
    xorwf    tablat,w    
    bnz    btplp2            ;loop till \0 or \n

    bra    btplp0            ;and test against next response

;match found, response bit set

btpmat

;match not found, non-standard response bit set

btpnmf

    return

btcmes    db    "AOK\n","ERR\n","Bonded\n","Secured\n","Connection End\n","Reboot\n",0,"CMD\n",'\r'


;***************************************************************
;** POLLBT -- Bluetooth polling -- called each main loop pass **
;***************************************************************

pollbt
    BANKSEL    btstate            ;select bluetooth working bank        

;if awaiting a response and timer=0, a receiver timeout occured

    movf    btswait,f,1        ;awaiting a response?
    bz    pbtnto            ;no, don't error on timeout

    movf    btstime,f,1        ;has timer expired?
    bz    pbtrto            ;yes, indicate it

pbtnto    movf    btstime,f,1        ;state timer expire?
    bz    ckrcv            ;yes, check receiver

    btfsc    tc16ms            ;process 16ms timer
    decf    btstime,f,1        ;decrement state timer


;process reciever before processing state machine

ckrcv    rcall    btprcv            ;process bluetooth receiver

;don't proceed until proper response has been received -- if required

    movf    btswait,w,1        ;are we waiting for a response?
    bz    pbstate            ;no, just process machine

    movf    btsresp,f,1        ;has a response been recieved?
    bz    ibtex            ;no, don't process sm this pass

;check for ERR response

    bbs    fsrerr,pbterr        ;ERR message received?

;test for correct response

    andwf    btsresp,w,1        ;has a proper response been received?
    bz    pbtimp            ;no, flag improper response

    bra    pbstate            ;and let sm continue in next state

;Handle improper response

pbtimp    movlw    btrto            ;set both to/err for improper response
    call    seterr

;Handle ERR response

pbterr    movlw    bterr            ;get ERR error code
    call    seterr            ;and show error
    bra    pbstate            ;try to limp along

;Handle timeout during reception of response

pbtrto    movlw    btrto            ;get time out error code
    call    seterr            ;and set error limp along

;process Bluetooth state machine

pbstate    clrf    btswait,1        ;clear waiting flags for next pass
    clrf    btstime,1        ;and state timer

    movfw    btstate
    call    cjump

    bra    bts0            ;state 0:  await BTAWAKE hardware line
    bra    bts1            ;state 1:  send feature string
    bra    bts2            ;state 2:  set friendly name
    bra    bts3            ;state 3:  set model name
    bra    bts4            ;state 4:  set manufacturer name
    bra    bts5            ;state 5:  start reboot
    bra    bts6            ;state 6:  wait for reboot to complete
    bra    bts7            ;state 7:  start advertising
    bra    bts8            ;state 8:  idle showing connection

;***********************
;** Bluetooth states  **
;***********************

;-- State 0:  await BTAWAKE hardware line, then wait 100ms

bts0    bbc    btawake,ibtex            ;exit if BTAWAKE not asserted

    movlfb    btstime,clctim(t16ms,115)    ;set up 100 ms timer
    bra    ibtns                ;and get out

;-- State 1: clear receive buffer, then send feature string

bts1    call    rxbyte                ;data in receive buffer?
    bnz    bts1                ;yes, keep reading till clear

    bsf    fbtinit                ;indicate initialized

    txpstr    sbtfs                ;send feature settings string
    bra    ibtexat

;-- State 2: set friendly name

bts2    txpstr    sbtfn                ;send friendly name
    bra    ibtexat

;-- State 3: set model name

bts3    txpstr    sbtmod                ;set model
    bra    ibtexat

;-- State 4: set manufacturer name

bts4    txpstr    sbtmnm                ;set manufacturer name
    bra    ibtexat

;-- State 5: reboot

bts5    txpstr    sbtres                ;send reset
    bsf    fwrrbt                ;wait for 'Reboot'
    bra    ibtext

;-- State 6: wait up to 3,200 ms for reboot sequence

bts6    bsf    fwrzcmd                ;wait for '\0CMD'
    movlfb    btstime,clctim(t16ms,3212)    ;up to 3212ms allowed for response
    bra    ibtns

;-- State 7: start advertisement

bts7    txpstr    sbtadv
    bra    ibtexat

;-- State 8:  idle for now

bts8    btfsc    btconn                ;connected?
    call    blon                ;turn on backlight to show we are connected
    btfss    btconn
    call    bloff                ;turn off for disconnected

    bra    ibtex

;set up next state with AOK response and 200ms timeout

ibtexat    bsf    FWRAOK                ;wait for 'AOK'

;set up next state with 200 ms timeout

ibtext    movlfb    btstime,clctim(t16ms,213)    ;up to 213ms allowed for response

;set up next state

ibtns    incf    btstate,f,1            ;and skip to next state on completion

;restore BSR and quit till next pass

ibtex    movlb    0
    return


;** Strings **

sbtfg    db    "gr\r\0"            ;get features
sbtfs    db    "sr,00060000\r\0"        ;no auto-advertise, no authentication
sbtfn    db    "s-,WECoyote\r\0"
sbtmod    db    "sdm,AAC1000\r\0"
sbtmnm    db    "sdn,Acme Products\r\0"
sbtres    db    "r,1\r\0"            ;reset
sbtadv    db    "A\r\0"                ;advertise
sbtunb    db    "U\r\0"
 
Last edited:

Thread Starter

joeyd999

Joined Jun 6, 2011
6,297
Oh, and here's some of the definitions for the above code:

Code:
;Bluetooth Flags

#define    fbtinit    btflag0,0,1        ;1=bluetooth initialized
;#define     btflag0,1,1        ;
;#define     btflag0,2,1        ;
;#define     btflag0,3,1        ;
;#define     btflag0,4,1        ;
;#define     btflag0,5,1        ;
;#define     btflag0,6,1        ;
;#define     btflag0,7,1        ;

;standard response flags

#define    FSRAOK    btsresp,0,1        ;"AOK"
#define    FSRERR    btsresp,1,1        ;"ERR"
#define    FSRBOND    btsresp,2,1        ;"BONDED"
#define    FSRSEC    btsresp,3,1        ;"SECURED"
#define    FSRCEND    btsresp,4,1        ;"CONNECTION END"
#define    FSRRBT    btsresp,5,1        ;"REBOOT"
#define FSRZCMD    btsresp,6,1        ;"\0CMD" (reply when reboot complete)
#define    FSRNSR    btsresp,7,1        ;non-standard response received

;wait for standard response flags

#define    FWRAOK    btswait,0,1        ;"AOK"
#define    FWRERR    btswait,1,1        ;"ERR"
#define    FWRBOND    btswait,2,1        ;"BONDED"
#define    FWRSEC    btswait,3,1        ;"SECURED"
#define    FWRCEND    btswait,4,1        ;"CONNECTION END"
#define    FWRRBT    btswait,5,1        ;"REBOOT"
#define FWRZCMD    btsresp,6,1        ;"\0CMD" (reply when reboot complete)
#define    FWRNSR    btswait,7,1        ;non-standard response received
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,297
Just curious:

Aside from @NorthGuy, does anyone find this interesting? If not, I won't bother wasting my time reporting here on my progress.

I at least expected someone to convince me of how much easier and efficient this would be in C. And then we could have another debate (Yay!).
 

cmartinez

Joined Jan 17, 2007
8,763
Just curious:

Aside from @NorthGuy, does anyone find this interesting? If not, I won't bother wasting my time reporting here on my progress.

I at least expected someone to convince me of how much easier and efficient this would be in C. And then we could have another debate (Yay!).
I definitely do... though my area of expertise is the 8051 architecture, which I plan to ditch soon and migrate to (probably) ARM
 

cmartinez

Joined Jan 17, 2007
8,763
I don't know about this. If I needed a medical device and couldn't program it myself, I would trust joyed999 to program it rather than anyone from the Arduino crowd :) Wouldn't you?
Truth being told... yes, I would... but I'll never admit that in front of Joey :p
 
Last edited:

atferrari

Joined Jan 6, 2004
5,012
Just curious:

Aside from @NorthGuy, does anyone find this interesting? If not, I won't bother wasting my time reporting here on my progress.
I definitely do. After working by myself a reasonable library (in Assembly) to work with multiple DS18S20, including the whole algorithm to identify unknown ICs on line, and then transmitting them through the RN42, I did not went into any complexity as in your code.

I believe in posting even if your "public" does not show up. One day you will be surprised how much people noticed what you did.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,297
I've made lots of changes to the parser in the last few hours. Since this is a stand-alone device, it needs to be absolutely robust so as not to "hang" or malfunction in the field. I'll post the complete parser when I'm done.

Here is where I am stuck now:

I am using an Android app called nRF Master Control Panel as my test platform. Everything works great until I try to set up private characteristics. The RN4020 accepts the new private characteristics and makes a connection with the Android via nRF just fine, but nRF hangs (the little "connecting" wheel spins and a connection is never made). I suspect it is being thrown by the presence of the private characteristics -- like it doesn't know what to do with them.

Anyone?
 
Top