Subversion Repositories HomeAutomation

Rev

Rev 68 | Rev 79 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *                  Main application
  4.  *
  5.  *********************************************************************
  6.  * FileName:        Main.c
  7.  *
  8.  * Author               Date    Comment
  9.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  10.  * Johan Böhlin     21-10-06    Original        (Rev 1.0)
  11.  ********************************************************************/
  12.  
  13. #include <compiler.h>
  14. #include <stackTasks.h>
  15. #include <CANdefs.h>
  16. #include <CAN.h>
  17. //#include <Tick.h>
  18. #include <boot.h>
  19.  
  20. /** V E C T O R  R E M A P P I N G *******************************************/
  21.  
  22. #pragma code _HIGH_INTERRUPT_VECTOR = 0x000008
  23. void _high_ISR (void)
  24. {
  25.     _asm goto RM_HIGH_INTERRUPT_VECTOR _endasm
  26. }
  27.  
  28. #pragma code _LOW_INTERRUPT_VECTOR = 0x000018
  29. void _low_ISR (void)
  30. {
  31.     _asm goto RM_LOW_INTERRUPT_VECTOR _endasm
  32. }
  33.  
  34. #pragma code
  35.  
  36.  
  37. #ifdef USE_CAN
  38.     #include <CAN.h>
  39. #endif
  40.  
  41. static CAN_PROTO_MESSAGE cm;
  42. static BYTE ful=0;
  43. static DWORD cnt =0;
  44.  
  45. static void mainInit(void);
  46. static BOOL canGetPacket(void);
  47. void TBLWT_Func(void);
  48. void TBLWTPOSTINC_Func (void);
  49. void TBLRD_Func(void);
  50.  
  51. #define TICK_SUB_COUNTER_10MS 312
  52. #define PACKET_TIMEOUT 14
  53. #define BOOTLOADER_INIT_TIMOUT 500
  54.  
  55. DWORD tickCounter = 0;
  56. DWORD tickSubCounter = 0;
  57.  
  58. DWORD tickGet(void);
  59.  
  60. void main()
  61. {
  62.     static PROGRAM_STATE pgs = pgsWATING_START;
  63.     static DWORD t = 0;
  64.     static WORD programmerSid=0;
  65.    
  66.     static BYTE errMsg = ERR_NO_ERROR;
  67.     static PROGRAM_STATE afterAckPgs = pgsWATING_START;
  68.     static DWORD pgmAddress = 0;
  69.     static BYTE bytesReceived = 0;
  70.  
  71.     DWORD tBoot;
  72.    
  73.     static BYTE pgmData[64];
  74.  
  75.     static BYTE tmp;
  76.  
  77.     // Inits
  78.     mainInit();
  79.  
  80.     #ifdef USE_CAN
  81.         canInit();
  82.     #endif
  83.  
  84.     tBoot = tickGet();
  85.    
  86.  
  87.     for(;;)
  88.     {
  89.         BYTE i;
  90.         CAN_PROTO_MESSAGE outCm;
  91.         BOOL hasPacket = canGetPacket();
  92.  
  93.         tickSubCounter++;
  94.         if (tickSubCounter>TICK_SUB_COUNTER_10MS)
  95.         {
  96.             tickCounter++;
  97.             tickSubCounter=0;
  98.         }
  99.  
  100.         switch(pgs)
  101.         {
  102.             case pgsWATING_START:
  103.                 // Check if there is bootloader start packet
  104.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && cm.funcc==FUNCC_BOOT_INIT && cm.data[RID_INDEX]==MY_ID && cm.nid==MY_NID)
  105.                 {
  106.                     // Has new start packet
  107.                     pgmAddress      = (((DWORD)cm.data[ADDRU_INDEX])<<16)+(((DWORD)cm.data[ADDRH_INDEX])<<8)+((DWORD)cm.data[ADDRL_INDEX]);
  108.                     programmerSid   = cm.sid;
  109.                     t               = tickGet();
  110.                     errMsg          = ERR_NO_ERROR;
  111.                     afterAckPgs     = pgsWAIT_FIRST_PGM_PACKET;
  112.                     pgs             = pgsSEND_ACK;
  113.                     // save pgm adress.
  114.                    
  115.                 }
  116.  
  117.                 // Bootloader timeout
  118.                 if ((tickGet()-tBoot)>BOOTLOADER_INIT_TIMOUT)
  119.                 {
  120.                     pgs = pgsDONE;
  121.                 }
  122.             break;         
  123.  
  124.             case pgsSEND_ACK:
  125.                 // send ack
  126.                 outCm.funct             = FUNCT_BOOTLOADER;
  127.                 outCm.funcc             = FUNCC_BOOT_ACK;
  128.                 outCm.nid               = MY_NID;
  129.                 outCm.sid               = MY_ID;
  130.                 outCm.data_length       = 8;
  131.                 outCm.remote_request    = FALSE;
  132.                 outCm.data[ERR_INDEX]   = errMsg;
  133.                 t                       = tickGet();
  134.                 pgs                     = afterAckPgs;
  135.  
  136.                 while(!canSendMessage(outCm,PRIO_HIGH));
  137.             break;
  138.  
  139.  
  140.             case pgsWAIT_FIRST_PGM_PACKET:
  141.                 // wait for first pgm packet.
  142.                 if ((tickGet()-t)>PACKET_TIMEOUT)
  143.                 {
  144.                     // Timeout, resend ack.
  145.                     errMsg          = ERR_NO_ERROR;
  146.                     afterAckPgs     = pgsWAIT_FIRST_PGM_PACKET;
  147.                     pgs             = pgsSEND_ACK;
  148.                 }
  149.  
  150.                 // If programming packet...
  151.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && (cm.funcc & 0x3)==FUNCC_BOOT_PGM && cm.nid==MY_NID && cm.sid==programmerSid)
  152.                 {
  153.                     BYTE localIndex = (BYTE)((cm.funcc & 0x1C)>>2)*8;
  154.  
  155.                     // Save bytes in memory, setup start adress etc..
  156.                     bytesReceived   = 8;       
  157.                     pgmData[localIndex+0]=cm.data[0]; pgmData[localIndex+1]=cm.data[1]; pgmData[localIndex+2]=cm.data[2]; pgmData[localIndex+3]=cm.data[3];
  158.                     pgmData[localIndex+4]=cm.data[4]; pgmData[localIndex+5]=cm.data[5]; pgmData[localIndex+6]=cm.data[6]; pgmData[localIndex+7]=cm.data[7];
  159.                
  160.                     pgs             = pgsWAIT_PGM_PACKET;
  161.                 }
  162.  
  163.  
  164.             break;
  165.  
  166.  
  167.             case pgsWAIT_PGM_PACKET:
  168.        
  169.            
  170.                 // If programming packet...
  171.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && (cm.funcc & 0x3)==FUNCC_BOOT_PGM && cm.nid==MY_NID && cm.sid==programmerSid)
  172.                 {
  173.                     BYTE localIndex = (BYTE)((cm.funcc & 0x1C)>>2)*8;
  174.                     // Save bytes in memory, inc received bytes.
  175.                     pgmData[localIndex+0]=cm.data[0]; pgmData[localIndex+1]=cm.data[1]; pgmData[localIndex+2]=cm.data[2]; pgmData[localIndex+3]=cm.data[3];
  176.                     pgmData[localIndex+4]=cm.data[4]; pgmData[localIndex+5]=cm.data[5]; pgmData[localIndex+6]=cm.data[6]; pgmData[localIndex+7]=cm.data[7];
  177.                    
  178.                     bytesReceived   += 8;
  179.                     pgs              = pgsWAIT_PGM_PACKET;
  180.                 }
  181.  
  182.                 // If adress packet (control packet)..
  183.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && cm.funcc==FUNCC_BOOT_ADDR && cm.nid==MY_NID && cm.sid==programmerSid)
  184.                 {
  185.                     // Send ack and goto wait first packet.
  186.                     // save adress.
  187.                     errMsg          = ERR_NO_ERROR;
  188.                     afterAckPgs     = pgsWAIT_FIRST_PGM_PACKET;
  189.                     pgs             = pgsSEND_ACK;
  190.                 }
  191.                
  192.                 // If end packet...
  193.                 if (hasPacket==TRUE && cm.funct==FUNCT_BOOTLOADER && cm.funcc==FUNCC_BOOT_DONE && cm.nid==MY_NID && cm.sid==programmerSid)
  194.                 {
  195.                     // write program.
  196.                     // If no bytes received at all, assume end.
  197.                     // If not 64 bytes received, send error ack and wait for first packet.
  198.                     // If 64, write.
  199.  
  200.                     if (bytesReceived==0)
  201.                     {
  202.                         // No received, done.
  203.                         errMsg          = ERR_NO_ERROR;
  204.                         afterAckPgs     = pgsDONE;
  205.                         pgs             = pgsSEND_ACK;
  206.                     }
  207.                     else if (bytesReceived!=64)
  208.                     {
  209.                         errMsg          = ERR_ERROR;
  210.                         afterAckPgs     = pgsWAIT_FIRST_PGM_PACKET;
  211.                         pgs             = pgsSEND_ACK;
  212.                     }
  213.                     else
  214.                     {
  215.                         pgs              = pgsWRITE_PROGRAM;
  216.                         afterAckPgs     = pgsDONE;
  217.                     }
  218.                 }
  219.  
  220.                 // If bytes received 64, write..
  221.                 if (bytesReceived==64)
  222.                 {
  223.                     LED0_IO=~LED0_IO;
  224.                     pgs              = pgsWRITE_PROGRAM;
  225.                     afterAckPgs     = pgsWAIT_PGM_PACKET;
  226.                     // TODO! Send ack more than once..
  227.                 }
  228.  
  229.  
  230.             break;
  231.  
  232.  
  233.             case pgsWRITE_PROGRAM:
  234.  
  235.  
  236.                 // Write program and send ack.
  237.  
  238.                 // Check addr limit
  239.                 if (pgmAddress<RM_RESET_VECTOR)
  240.                 {              
  241.                     errMsg          = ERR_ERROR;
  242.                     pgs             = pgsSEND_ACK;
  243.                     //Not allowed to write here!
  244.                    
  245.                 }
  246.  
  247.                 //Load Table pointer registers with base address to erase.
  248.                 TBLPTRU = (BYTE)((pgmAddress & 0xFF0000)>>16);
  249.                 TBLPTRH = (BYTE)((pgmAddress & 0xFF00)>>8);
  250.                 TBLPTRL = (BYTE)(pgmAddress & 0xFF);
  251.  
  252.                 // point to Flash program memory
  253.                 EECON1bits.EEPGD = 1;
  254.                 // access Flash program memory
  255.                 EECON1bits.CFGS = 0;
  256.                 // enable write to memory
  257.                 EECON1bits.WREN = 1;
  258.                 // enable Row Erase operation
  259.                 EECON1bits.FREE = 1;
  260.                 // disable interrupts
  261.                 INTCONbits.GIE = 0;
  262.  
  263.                 // Do it!
  264.                 EECON2 = 0x55;
  265.                 EECON2 = 0xAA;
  266.                 EECON1bits.WR = 1;
  267.  
  268.                 // enable interrupts
  269.                 INTCONbits.GIE = 1;
  270.                
  271.                 //Load Table pointer registers with base address to program.
  272.                 TBLPTRU = (BYTE)((pgmAddress & 0xFF0000)>>16);
  273.                 TBLPTRH = (BYTE)((pgmAddress & 0xFF00)>>8);
  274.                 TBLPTRL = (BYTE)(pgmAddress & 0xFF);
  275.  
  276.                 // Load bytes
  277.                 for(i=0;i<63;i++)
  278.                 {
  279.                     TABLAT=pgmData[i];
  280.                     TBLWTPOSTINC_Func();
  281.                 }
  282.                 TABLAT=pgmData[63];
  283.                 TBLWT_Func();
  284.  
  285.  
  286.                 // point to Flash program memory
  287.                 EECON1bits.EEPGD = 1;
  288.                 // access Flash program memory
  289.                 EECON1bits.CFGS = 0;
  290.                 // enable write to memory
  291.                 EECON1bits.WREN = 1;
  292.                 // disable interrupts
  293.                 INTCONbits.GIE = 0;
  294.                
  295.                 // Do it!
  296.                 EECON2 = 0x55;
  297.                 EECON2 = 0xAA;
  298.                 EECON1bits.WR = 1;
  299.  
  300.                 // enable interrupts
  301.                 INTCONbits.GIE = 1;
  302.  
  303.                 // disable write to memory
  304.                 EECON1bits.WREN = 0;
  305.  
  306.                 pgmAddress     += 64;
  307.                 bytesReceived   = 0;
  308.                 errMsg          = ERR_NO_ERROR;
  309.                 pgs             = pgsSEND_ACK;
  310.  
  311.             break;
  312.  
  313.  
  314.             case pgsDONE:
  315.                 _asm  goto RM_RESET_VECTOR _endasm
  316.             break;
  317.  
  318.        
  319.  
  320.  
  321.             default:
  322.                 pgs = pgsWATING_START;
  323.             break;
  324.         }
  325.    
  326.  
  327.     }
  328. }
  329.  
  330.  
  331. /*
  332. *   Function: mainInit
  333. *
  334. *   Input:  none
  335. *   Output: none
  336. *   Pre-conditions: none
  337. *   Affects: Se code
  338. *   Depends: none.
  339. */
  340. void mainInit()
  341. {
  342.     LED0_TRIS=0;   
  343.  
  344.     // Enable internal PORTB pull-ups
  345.     INTCON2bits.RBPU = 0;
  346.    
  347.     // Enable Interrupts
  348.     INTCONbits.GIEH = 1;
  349.     INTCONbits.GIEL = 1;
  350.  
  351.     // Enable interrupt prirority
  352.     RCONbits.IPEN=1;
  353.    
  354.  
  355. }
  356.  
  357.  
  358.  
  359. /// CAN-------------------------------------------------------
  360.  
  361.  
  362. #ifdef USE_CAN
  363.  
  364.  
  365. /*
  366. *   Function: canInit
  367. *
  368. *   Input:  none
  369. *   Output: none
  370. *   Pre-conditions: none
  371. *   Affects: Changes can registers.
  372. *   Depends: none.
  373. */
  374. void canInit()
  375. {
  376.     CANCON = 0x80; //request config mode
  377.     while ((CANSTAT & 0xE0) != 0x80 ); //wait for config mode request
  378.  
  379.     // BAUD AND TQS
  380.  
  381.     BRGCON1=0;
  382.    
  383.     // Sync_Seq = 2 x TQ = 1
  384.     BRGCON1bits.SJW1=0;
  385.     BRGCON1bits.SJW0=1;
  386.    
  387.     // Setting BRP.
  388.     BRGCON1=BRGCON1|CAN_BRP;
  389.    
  390.     // Maximum PHEG1
  391.     BRGCON2bits.SEG2PHTS = 1;
  392.    
  393.     // Phase_Seg1 = 2 x TQ = 1
  394.     BRGCON2bits.SEG1PH2 = 0;
  395.     BRGCON2bits.SEG1PH1 = 0;
  396.     BRGCON2bits.SEG1PH0 = 1;
  397.    
  398.     // Prop_Seq = 2 x TQ = 1
  399.     BRGCON2bits.PRSEG2 = 0;
  400.     BRGCON2bits.PRSEG1 = 0;
  401.     BRGCON2bits.PRSEG0 = 1;
  402.    
  403.     //  Enableing bus wake-up
  404.     BRGCON3bits.WAKDIS = 0;
  405.    
  406.     // Dont use filter when wakeup
  407.     BRGCON3bits.WAKFIL = 0;
  408.    
  409.     // Phase_Seg2 = 2 x TQ = 1
  410.     BRGCON3bits.SEG2PH2 = 0;
  411.     BRGCON3bits.SEG2PH1 = 0;
  412.     BRGCON3bits.SEG2PH0 = 1;
  413.  
  414.     ECANCON=0;
  415.     ECANCONbits.MDSEL1 = 0;
  416.     ECANCONbits.MDSEL0 = 1;
  417.  
  418.  
  419.     // FILTERS AND MASKS
  420.     RXB0CONbits.RXM1=1;
  421.     RXB0CONbits.RXM0=0;
  422.  
  423.  
  424.     // INTERRUPTS
  425.    
  426.     // Diable transmit interrupt
  427.     TXBIE = 0;
  428.  
  429.     //rx no interrupt
  430.     PIR3 = 0;
  431.     PIE3 = 0;
  432.  
  433.  
  434.     // Programmable no buffers interrupt
  435.     BIE0  = 0x00;  
  436.  
  437.  
  438.     //loopback mode or not
  439.     #ifdef CAN_LOOPBACK_MODE
  440.         CANCON = 0x40;//request loopback mode
  441.         while ((CANSTAT & 0xE0) != 0x40 );//wait for loopback mode
  442.     #else
  443.         CANCON = 0x00;//request normal mode
  444.         while ((CANSTAT & 0xE0) != 0x00 );//wait for normal mode
  445.     #endif
  446.  
  447. }
  448.  
  449.  
  450.  
  451.  
  452. /*
  453. *   Function: canGetPacket
  454. *
  455. *   Input:  none
  456. *   Output: none
  457. *   Pre-conditions: a call to canISR and an packet is available and banked to RXB0
  458. *   Affects: Calls canParse() function in main for parsing received packet.
  459. *   Depends: none.
  460. */
  461. BOOL canGetPacket()
  462. {
  463.  
  464.         // Get which buffer that is ful.
  465.              if (RXB0CONbits.RXFUL) { ECANCON=(ECANCON&0b00000)|0b10000;  }
  466.         else if (RXB1CONbits.RXFUL) { ECANCON=(ECANCON&0b00000)|0b10001;  }
  467.         else if (B0CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10010;  }
  468.         else if (B1CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10011;  }
  469.         else if (B2CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10100;  }
  470.         else if (B3CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10101;  }
  471.         else if (B4CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10110;  }
  472.         else if (B5CONbits.RXFUL)   { ECANCON=(ECANCON&0b00000)|0b10111;  }
  473.         else return FALSE;
  474.  
  475.  
  476.         //RXB0SIDH 28 27 26 25 24 23 22 21
  477.         //RXB0SIDL 20 19 18 xx xx xx 17 16
  478.         //RXB0EIDH 15 14 13 12 11 10 09 08
  479.         //RXB0EIDL 07 06 05 04 03 02 01 00
  480.  
  481.         //funct xx xx xx xx 28 27 26 25
  482.         //funcc xx xx xx xx xx xx 24 23 22 21 20 19 18 17 16 15
  483.         //nid   xx xx 14 13 12 11 10 09
  484.         //sid   xx xx xx xx xx xx xx 08 07 06 05 04 03 02 01 00
  485.  
  486.  
  487.         cm.funct=((RXB0SIDH & 0xF0)>>4);
  488.         cm.funcc=(((WORD)(RXB0SIDH & 0x0F))<<6)+(((WORD)(RXB0SIDL & 0xE0))>>2)+(((WORD)(RXB0SIDL & 0x03))<<1)+(((WORD)(RXB0EIDH & 0x80))>>7);
  489.         cm.nid=((RXB0EIDH & 0x7E)>>1);
  490.         cm.sid=(((WORD)(RXB0EIDH & 0x01))<<8)+RXB0EIDL;
  491.  
  492.  
  493.         // Data length
  494.         cm.data_length=(RXB0DLCbits.DLC3<<3)+(RXB0DLCbits.DLC2<<2)+(RXB0DLCbits.DLC1<<1)+RXB0DLCbits.DLC0;
  495.  
  496.         // Remote request
  497.         cm.remote_request=(RXB0DLCbits.RXRTR==0?FALSE:TRUE);
  498.  
  499.         // Data one bye one, for speed
  500.         cm.data[0]=RXB0D0;  cm.data[1]=RXB0D1;
  501.         cm.data[2]=RXB0D2;  cm.data[3]=RXB0D3;
  502.         cm.data[4]=RXB0D4;  cm.data[5]=RXB0D5;
  503.         cm.data[6]=RXB0D6;  cm.data[7]=RXB0D7;
  504.  
  505.         // Clear ful status
  506.         RXB0CONbits.RXFUL=0;
  507.  
  508.         return TRUE;
  509. }
  510.  
  511.  
  512. /*
  513. *   Function: canSendMessage
  514. *
  515. *   Input:  CAN_MESSAGE to send
  516. *   Output: True if packet scheduled sucess, false otherwise.
  517. *   Pre-conditions: canInit
  518. *   Affects: ..
  519. *   Depends: ..
  520. */
  521. BOOL canSendMessage(CAN_PROTO_MESSAGE cm,CAN_PRIORITY prio)
  522. {
  523.    
  524.     if ( TXB0CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00011; }
  525.     if ( TXB1CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00100; }
  526.     if ( TXB2CONbits.TXREQ == 0 )  { ECANCON=(ECANCON&0b00000)|0b00101; }
  527.     // None of the transmit buffers were empty.
  528.     else { return FALSE;}
  529.  
  530.     if (prio<0 || prio>3) prio = 0;
  531.  
  532.  
  533.         //RXB0SIDH 28 27 26 25 24 23 22 21
  534.         //RXB0SIDL 20 19 18 xx xx xx 17 16
  535.         //RXB0EIDH 15 14 13 12 11 10 09 08
  536.         //RXB0EIDL 07 06 05 04 03 02 01 00
  537.  
  538.         //funct xx xx xx xx 28 27 26 25
  539.         //funcc xx xx xx xx xx xx 24 23 22 21 20 19 18 17 16 15
  540.         //nid   xx xx 14 13 12 11 10 09
  541.         //sid   xx xx xx xx xx xx xx 08 07 06 05 04 03 02 01 00
  542.  
  543.         RXB0SIDH = (BYTE)((cm.funct & 0x0F)<<4)+(BYTE)((cm.funcc & 0x03C0)>>6);
  544.         RXB0SIDL = (BYTE)((cm.funcc & 0x003F)<<2)+(BYTE)((cm.funcc & 0x0006)>>1);
  545.         RXB0EIDH = (BYTE)((cm.funcc & 0x0001)<<7)+(BYTE)((cm.nid & 0x3F)<<1)+(BYTE)((cm.sid & 0x0100)>>8);
  546.         RXB0EIDL = (BYTE)((cm.sid & 0x00FF));
  547.  
  548.         // Data length
  549.         RXB0DLC = 0;
  550.         if (cm.data_length>8) RXB0DLC=8; else RXB0DLC=cm.data_length;
  551.        
  552.         // Remote request
  553.         if (cm.remote_request==TRUE)
  554.         {
  555.             _asm
  556.                 bsf RXB0DLC, 6, 0
  557.             _endasm
  558.         }
  559.         else
  560.         {
  561.             _asm
  562.                 bcf RXB0DLC, 6, 0
  563.             _endasm
  564.         }
  565.  
  566.         // Data one bye one, for speed
  567.         RXB0D0=cm.data[0];  RXB0D1=cm.data[1];
  568.         RXB0D2=cm.data[2];  RXB0D3=cm.data[3];
  569.         RXB0D4=cm.data[4];  RXB0D5=cm.data[5];
  570.         RXB0D6=cm.data[6];  RXB0D7=cm.data[7];
  571.  
  572.         // set extended or not
  573.         RXB0SIDLbits.EXID=1;
  574.  
  575.         // Priority
  576.         RXB0CON = (RXB0CON & 0b11111100) | prio;
  577.  
  578.         // mark as redy to transmit
  579.         _asm
  580.             bsf RXB0CON, 3, 0
  581.         _endasm
  582.  
  583.         return TRUE;
  584.  
  585. }
  586.  
  587.  
  588.  
  589. #endif //USE_CAN
  590.  
  591.  
  592.  
  593.  
  594. void TBLRD_Func()
  595. {
  596. _asm
  597.     TBLRD
  598. _endasm
  599. }
  600.  
  601. void TBLWT_Func()
  602. {
  603. _asm
  604.     TBLWT
  605. _endasm
  606. }
  607.  
  608.  
  609. void TBLWTPOSTINC_Func (void){
  610. _asm
  611.     TBLWTPOSTINC
  612. _endasm
  613. }
  614.  
  615. DWORD tickGet()
  616. {
  617.     return tickCounter;
  618. }
  619.  
  620.  
  621. #pragma code user = RM_RESET_VECTOR
  622.