1 // ************************************************************************** 2 // Custom DPA Handler code example - User peripheral supporting UART HW * 3 // ************************************************************************** 4 // Copyright (c) MICRORISC s.r.o. 5 // 6 // File: $RCSfile: CustomDpaHandler-UserPeripheral-HW-UART.c,v $ 7 // Version: $Revision: 1.22 $ 8 // Date: $Date: 2022/02/25 09:41:25 $ 9 // 10 // Revision history: 11 // 2022/02/24 Release for DPA 4.17 12 // 2017/08/14 Release for DPA 3.01 13 // 14 // ********************************************************************* 15 16 // Online DPA documentation https://doc.iqrf.org/DpaTechGuide/ 17 18 // This example implements the user peripheral supporting HW UART of the PIC 19 // This example works only at STD mode, not at LP mode 20 // RX = RC7 21 // TX = RC6 22 23 // Default IQRF include (modify the path according to your setup) 24 #include "IQRF.h" 25 26 // Default DPA header (modify the path according to your setup) 27 #include "DPA.h" 28 // Default Custom DPA Handler header (modify the path according to your setup) 29 #include "DPAcustomHandler.h" 30 31 //############################################################################################ 32 33 // TX byte to UART 34 void TxUART( uns8 data ); 35 // RX byte from UART; W = read byte, Carry = byte was read 36 bit RxUART(); 37 38 //############################################################################################ 39 40 // UART baud rate 41 #define UART_BAUD 19200 42 43 // Number of UART received bytes 44 uns8 RxDataLengthUART; 45 46 // Length of RX and TX buffers, must be power of 2 47 #define UART_BUFFER_LENGTH 16 48 49 #if 0 != ( UART_BUFFER_LENGTH & ( UART_BUFFER_LENGTH - 1 ) ) 50 #error UART_BUFFER_LENGTH is not power of 2 51 #endif 52 53 // Rx 54 // Circular RX UART buffer pointers 55 uns8 RxBufferPointerStartUART; 56 uns8 RxBufferPointerEndUART; 57 uns8 RxBufferUART[UART_BUFFER_LENGTH] /*@ PeripheralRam[0]*/; 58 59 // TX 60 // Circular TX UART buffer pointers 61 uns8 TxBufferPointerStartUART; 62 uns8 TxBufferPointerEndUART; 63 uns8 TxBufferUART[UART_BUFFER_LENGTH] /*@ PeripheralRam[UART_BUFFER_LENGTH]*/; 64 65 // Division macro with rounding 66 #define DIV(Dividend,Divisor) (((Dividend+((Divisor)>>1))/(Divisor))) 67 // PIC baud register computation 68 #define UART_SPBRG_VALUE( Baud ) ( DIV( F_OSC, ( ( ( uns24 )4 ) * ( Baud ) ) ) - 1 ) 69 70 71 // Must be the 1st defined function in the source code in order to be placed at the correct FLASH location! 72 //############################################################################################ 73 bit CustomDpaHandler() 74 //############################################################################################ 75 { 76 // Handler presence mark 77 clrwdt(); 78 79 // TXIE state before sleep 80 static bit wasTXIE; 81 82 // Detect DPA event to handle 83 switch ( GetDpaEvent() ) 84 { 85 // ------------------------------------------------- 86 case DpaEvent_Interrupt: 87 // Do an extra quick background interrupt work 88 // ! The time spent handling this event is critical.If there is no interrupt to handle return immediately otherwise keep the code as fast as possible. 89 // ! Make sure the event is the 1st case in the main switch statement at the handler routine.This ensures that the event is handled as the 1st one. 90 // ! It is desirable that this event is handled with immediate return even if it is not used by the custom handler because the Interrupt event is raised on every MCU interrupt and the “empty” return handler ensures the shortest possible interrupt routine response time. 91 // ! Only global variables or local ones marked by static keyword can be used to allow reentrancy. 92 // ! Make sure race condition does not occur when accessing those variables at other places. 93 // ! Make sure( inspect.lst file generated by C compiler ) compiler does not create any hidden temporary local variable( occurs when using division, multiplication or bit shifts ) at the event handler code.The name of such variable is usually Cnumbercnt. 94 // ! Do not call any OS functions except setINDFx(). 95 // ! Do not use any OS variables especially for writing access. 96 // ! All above rules apply also to any other function being called from the event handler code, although calling any function from Interrupt event is not recommended because of additional MCU stack usage. 97 98 // ----------------------------------------------------------------------------------------- 99 // UART Receive 100 // 101 if ( RCIF ) 102 { 103 // We ignore FERR 104 FSR1L = _RCREG; 105 // Put the received byte in circular buffer 106 if ( RxDataLengthUART < UART_BUFFER_LENGTH ) 107 { 108 // One more byte received 109 RxDataLengthUART++; 110 // Prepare pointer 111 FSR0 = RxBufferUART + RxBufferPointerEndUART; 112 // Recalculate tail pointer 113 // Optimization: Same as (UART_BUFFER_LENGTH is power of 2) : RxBufferPointerEndUART = ( RxBufferPointerEndUART + 1 ) % UART_BUFFER_LENGTH; 114 RxBufferPointerEndUART++; 115 RxBufferPointerEndUART &= ~UART_BUFFER_LENGTH; 116 // Store byte 117 setINDF0( FSR1L ); 118 } 119 } 120 121 // Overrun recovery (we do it after receiving UART byte in order to receive it as soon as possible) 122 if ( OERR ) 123 CREN = 0; 124 125 // Seems excess, but at the end it is shorted and faster than having this statement at else branch 126 CREN = 1; 127 128 // ----------------------------------------------------------------------------------------- 129 // UART Transmit 130 // 131 if ( TXIF && TXIE ) 132 { 133 // Send byte from circular buffer to the UART 134 FSR0 = TxBufferUART + TxBufferPointerStartUART; 135 TxBufferPointerStartUART = ( TxBufferPointerStartUART + 1 ) % UART_BUFFER_LENGTH; 136 // Buffer empty? 137 if ( TxBufferPointerStartUART == TxBufferPointerEndUART ) 138 TXIE = FALSE; 139 // TX the byte 140 _TXREG = *FSR0; 141 } 142 143 // Return value does not matter 144 return Carry; 145 146 147 // ------------------------------------------------- 148 case DpaEvent_DpaRequest: 149 // Called to interpret DPA request for peripherals 150 // ------------------------------------------------- 151 // Peripheral enumeration 152 if ( IsDpaEnumPeripheralsRequest() ) 153 { 154 // We implement 1 user peripheral 155 _DpaMessage.EnumPeripheralsAnswer.UserPerNr |= 1; 156 FlagUserPer( _DpaMessage.EnumPeripheralsAnswer.UserPer, PNUM_USER + 0 ); 157 _DpaMessage.EnumPeripheralsAnswer.HWPID |= 0x000F; 158 _DpaMessage.EnumPeripheralsAnswer.HWPIDver |= 0x0000; 159 160 DpaHandleReturnTRUE: 161 return TRUE; 162 } 163 // ------------------------------------------------- 164 // Get information about peripheral 165 else if ( IsDpaPeripheralInfoRequest() ) 166 { 167 if ( _PNUM == PNUM_USER + 0 ) 168 { 169 _DpaMessage.PeripheralInfoAnswer.PerT = PERIPHERAL_TYPE_USER_AREA; 170 _DpaMessage.PeripheralInfoAnswer.PerTE = PERIPHERAL_TYPE_EXTENDED_READ_WRITE; 171 goto DpaHandleReturnTRUE; 172 } 173 174 break; 175 } 176 // ------------------------------------------------- 177 else 178 { 179 // Handle peripheral command 180 if ( _PNUM == PNUM_USER + 0 ) 181 { 182 // Check command 183 switch ( _PCMD ) 184 { 185 // ------------------------------ 186 // Write to UART 187 case 0: 188 // There must be some data to write 189 if ( _DpaDataLength == 0 ) 190 { 191 _ERROR_DATA_LEN: 192 DpaApiReturnPeripheralError( ERROR_DATA_LEN ); 193 } 194 195 // Pointer to data (setFSR1( _FSR_RF ) can be used too to save code) 196 FSR1 = &_DpaMessage.Request.PData[0]; 197 do 198 { 199 // Send one byte 200 TxUART( *FSR1++ ); 201 // Loop all bytes 202 } while ( --_DpaDataLength != 0 ); 203 204 // _DpaDataLength = 0 => no data returned 205 goto DpaHandleReturnTRUE; 206 207 // ------------------------------ 208 // Read from UART 209 case 1: 210 // No data must be sent 211 if ( _DpaDataLength != 0 ) 212 goto _ERROR_DATA_LEN; 213 214 // Pointer to the output buffer (setFSR1( _FSR_RF ) can be used too to save code) 215 FSR1 = &_DpaMessage.Response.PData[0]; 216 // Initial count of received bytes 217 _DpaDataLength = 0; 218 // Loop while there is enough space and some byte to read 219 while ( _DpaDataLength < sizeof( _DpaMessage.Response.PData ) && RxUART() ) 220 { 221 // Store read byte 222 setINDF1( W ); 223 // Move pointer 224 FSR1++; 225 // Count next byte 226 _DpaDataLength++; 227 } 228 229 // Return number of read bytes 230 goto DpaHandleReturnTRUE; 231 } 232 } 233 } 234 break; 235 236 // ------------------------------------------------- 237 case DpaEvent_Init: 238 // Do a one time initialization before main loop starts 239 240 // Connected TR pins (e.g. TR72D)? 241 moduleInfo(); 242 if ( !bufferINFO[5].7 ) 243 { 244 // Set them as inputs 245 TRISC.5 = 1; 246 TRISA.5 = 1; 247 TRISB.4 = 1; 248 } 249 250 // RX input 251 TRISC.7 = 1; 252 // TX output 253 TRISC.6 = 0; 254 255 #if defined( TR7xG ) 256 UART1MD = 0; 257 unlockPPS(); 258 RC6PPS = 0x10; // TX (Note: RX does not have to be set, use default) 259 lockPPS(); 260 #endif 261 262 // Set baud rate 263 _SPBRGL = UART_SPBRG_VALUE( UART_BAUD ) & 0xff; 264 _SPBRGH = UART_SPBRG_VALUE( UART_BAUD ) >> 8; 265 // baud rate control setup: BRG16 = 1 266 #if defined( TR7xG ) 267 setBAUD1CON( 0b0000.1.000 ); 268 #else 269 BAUDCON = 0b0000.1.000; 270 #endif 271 272 // CSRC TX9 TXEN SYNC SENDB BRGH TRMT TX9D 273 // TXEN = 1 274 // BRGH = 1 275 // async UART, high speed, 8 bit, TX enabled 276 #if defined( TR7xG ) 277 setTX1STA( 0b0010.0100 ); 278 #else 279 TXSTA = 0b0010.0100; 280 #endif 281 282 // SPEN RX9 SREN CREN ADDEN FERR OERR RX9D 283 // SPEN = 1 284 // CREN = 1 285 // Continuous receive, enable port, 8 bit 286 _RCSTA = 0b1001.0000; 287 // Enable UART RX interrupt 288 RCIE = TRUE; 289 290 break; 291 292 // ------------------------------------------------- 293 case DpaEvent_AfterSleep: 294 // Called after woken up after sleep 295 296 TXIE = wasTXIE; 297 RCIE = TRUE; 298 break; 299 300 // ------------------------------------------------- 301 case DpaEvent_BeforeSleep: 302 // Called before going to sleep 303 304 // ------------------------------------------------- 305 case DpaEvent_DisableInterrupts: 306 // Called when device needs all hardware interrupts to be disabled (before Reset, Restart, LoadCode, Remove bond, and Run RFPGM) 307 308 wasTXIE = TXIE; 309 TXIE = FALSE; 310 RCIE = FALSE; 311 break; 312 } 313 314 return FALSE; 315 } 316 317 //############################################################################################ 318 // Note: make sure the parameter does not overlap another variable as the function is ready to be called from (timer) interrupt too 319 static uns8 _data; 320 void TxUART( uns8 data @ _data ) 321 //############################################################################################ 322 { 323 // Wait for a space in the buffer 324 while ( TXIE && TxBufferPointerStartUART == TxBufferPointerEndUART ); 325 326 // Disable TX interrupt 327 TXIE = FALSE; 328 // Compute pointer 329 FSR0 = TxBufferUART + TxBufferPointerEndUART; 330 // Optimization: TxBufferPointerEndUART = ( TxBufferPointerEndUART + 1 ) % UART_BUFFER_LENGTH; 331 TxBufferPointerEndUART++; 332 TxBufferPointerEndUART &= ~UART_BUFFER_LENGTH; 333 // Store byte 334 setINDF0( _data ); 335 // Start transmitting 336 TXIE = TRUE; 337 } 338 339 //############################################################################################ 340 // W = read byte, Carry = result 341 bit RxUART() 342 //############################################################################################ 343 { 344 // Buffer empty? 345 if ( RxDataLengthUART == 0 ) 346 return FALSE; 347 348 // Disable RX interrupt 349 RCIE = FALSE; 350 // Get byte from the circular buffer 351 FSR0 = RxBufferUART + RxBufferPointerStartUART; 352 // Optimization: RxBufferPointerStartUART = ( RxBufferPointerStartUART + 1 ) % UART_BUFFER_LENGTH; 353 RxBufferPointerStartUART++; 354 RxBufferPointerStartUART &= ~UART_BUFFER_LENGTH; 355 // One byte less 356 RxDataLengthUART--; 357 // Returned byte 358 W = *FSR0; 359 // Enable RX interrupt 360 RCIE = TRUE; 361 // TRUE => byte was read 362 return TRUE; 363 } 364 365 //############################################################################################ 366 // Default Custom DPA Handler header; 2nd include implementing a Code bumper to detect too long code of the Custom DPA Handler (modify the path according to your setup) 367 #include "DPAcustomHandler.h" 368 //############################################################################################