• Forums
• Posts
Latest Posts
Active Posts
Recently Visited
Search Results
• Page Extras
• Forum Themes
• AVR Freaks

### PLACEHOLDER FOR Code Module Library

Page: < 123 > Showing page 2 of 3
Author
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
itoa() by Cawilkie: 2008/05/22 07:57:00 (permalink)
0
itoa() by Cawilkie:
`   #include <stdio.h>   char *itoa(char *buffer, int i) {  unsigned int n;  unsigned int negate = 0;  int c = 6;   if (i < 0) {  negate=1;  n = -i;  } else if (i == 0) {  buffer[0] = '0';  buffer[1] = 0;  return buffer;  } else {  n = i;  }  buffer[c--] = 0;  do {  buffer[c--] = (n % 10) + '0';  n = n / 10;  } while (n);  if (negate) {  buffer[c--] = '-';  }  return &buffer[c+1];  }   `

( http://forum.microchip.com/fb.aspx?m=240997 )

post edited by DarioG - 2010/12/27 03:04:28

GENOVA :D :D ! GODO
davepfz
Starting Member
• Total Posts : 39
• Reward points : 0
• Joined: 2004/08/21 06:07:14
• Status: offline
RE: Basic code for a Stepper Motor on PIC18F2420 2008/05/23 13:27:20 (permalink)
0
Since printing of floating point numbers has been a frequent issue here, I thought I'd provide a solution that works for me. The previous solutions did not allow for very large or small numbers, but this does in that it prints the number in very FOTRAN like format.

Use it with caution and test, test, test. Otherwise, enjoy!

/*  PrintFloat(Number, Buffer)
*
*  The PrintFloat routine takes a floating point number and converts it to a string located
*  at Buffer. The format of the string is in the 'scientific' notation of Sx.xxxESxx where
*  the Sx.xxx is a signed number between 1.000 and 9.999 and the Sxx is the signed exponent.
*
*  Although this is the format chosen here, it is easily extended to add digits, etc. Just
*  remember that the precision is limited by the underlying floating point library being used.
*
*  Cautions:
*    - It is up to the calling routine to ensure that there is ample buffer space.
*    - Be forewarned that the log10() and pow() routines are both memory and time hogs!
*/

#include   <math.h>

void PrintFloat(float Number, char *Buffer) {
char Sign, ExpSign;
int Exponent;
float LogNumber, Mantissa;

if (Number < 0.0) {                     // First capture the sign of the number
Sign = '-';
Number = -Number;                   // Now, the number is positive (required for log10()
} else {
Sign = ' ';
}
LogNumber = log10(Number);              // Find the logarithm
if (LogNumber < 0.0) {                  // Cature the sign of the exponent
ExpSign = '-';
LogNumber = -LogNumber;             // Now, the exponent is also positive
} else {
ExpSign = '+';
}
Exponent = (int)LogNumber;              // Keep the integer portion of the logarithm
Mantissa = LogNumber - (float)Exponent; // Find the frational part
Number = pow(10.0, Mantissa);           // Extract the 'normalized' number
sprintf(Buffer, "%c%d.%03dE%c%d", Sign, (int)Number, (int)(1000.0 * (Number - (int)Number + 0.0005)), ExpSign, Exponent);
return;
}

post edited by davepfz - 2008/05/29 10:18:59
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
a smarter (genius etc grin grin) PWM by Mike (K8LH) - BAM 2008/05/23 15:24:28 (permalink)
0
a smarter (genius etc ) PWM by Mike (K8LH)
`   ;  ;  Mike McLaren, K8LH  ;  Micro Application Consultants  ;  ;  ;  unsigned char Interval = 0;                               // 0..99  ;  unsigned char PWM[] = { 99, 99, 99, 14, 3, 0, 99, 0 };    // 0..99 duty cycle  ;  unsigned char Toggle[] = { 0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0,  ;                             0,0,0,0,0,0,0,0,0,0 };  ;  ;  ;  void pwm_isr()  ;  { PIR1bits.TMR2IF = 0;               // clear timer 2 interrupt flag  ;    LATB ^= Toggle[Interval];          // update outputs  ;    Toggle[Interval++] = 0;            // clear element for next period  ;    if(Interval = 100)                 // if end of period, rebuild array  ;    { Toggle[PWM[0]] |= 0b00000001;    // insert b0 toggle point  ;      Toggle[PWM[1]] |= 0b00000010;    // insert b1 toggle point  ;      Toggle[PWM[2]] |= 0b00000100;    // insert b2 toggle point  ;      Toggle[PWM[3]] |= 0b00001000;    // insert b3 toggle point  ;      Toggle[PWM[4]] |= 0b00010000;    // insert b4 toggle point  ;      Toggle[PWM[5]] |= 0b00100000;    // insert b5 toggle point  ;      Toggle[PWM[6]] |= 0b01000000;    // insert b6 toggle point  ;      Toggle[PWM[7]] |= 0b10000000;    // insert b7 toggle point  ;      Interval = 0;                    // reset Interval for new period  ;      Toggle[0] ^= 0xFF;               // invert first element  ;    }  ;  }   `

(comes from here
http://forum.microchip.com/tm.aspx?m=336389
)

post edited by DarioG - 2010/12/27 03:03:59

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
ASM30 template for PIC24: 2008/10/06 08:31:40 (permalink)
0
ASM30 template for PIC24:

`   ;------------------------------------------------------------------------------  ; Listing Controls  ;------------------------------------------------------------------------------  .psize 0              ; 0 = do not break listing by pages  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; Turn on the global visibility of the following symbols:  ;------------------------------------------------------------------------------  ;  These symbols are declared in a linker script - do not change their names:  .global__reset                ; Turn on the global visibility of the code start label  .global __SPI2Interrupt         ; Turn on the global visibility of the SPI 2 ISR label  .global __U2RXInterrupt        ; Turn on the global visibility of the UART 2 receive ISR label  .global__T1Interrupt          ; Turn on the global visibility of the Timer 1 ISR label  ; Put here other ISR global names if required   .global __ReservedTrap0        ; Turn on the global visibility of the error traps ISR label  .global __OscillatorFail        ;  .global __AddressError          ;  .global __StackError            ;  .global __MathError             ;  .global __ReservedTrap5         ;  .global __ReservedTrap6         ;  .global __ReservedTrap7         ;   ;  These names are arbitrary:  ;.global       xtal           ; Uncomment for crystal resonator clock instead of internal RC clock   ;------------------------------------------------------------------------------  ; Processor Setup  ;------------------------------------------------------------------------------  .include       "p24hj128gp206.inc"        ; Changeto your particular MCU type  .list   ;------------------------------------------------------------------------------  ; Equates & Symbols  ;------------------------------------------------------------------------------  fxtal   = 8000000       ; External quartz crystal frequency, Hz  ffrc    = 7372800       ; Internal fast RC oscillatot factory default frequency, Hz  plldiv  = 4             ; PLL postscaler value (minimal)   .ifdecl xtal            ; PLL multiplier value calculation for ~40 MIPS:  fosc    = fxtal         ; Main oscillatot frequency, Hz  pllmul  = 40            ; PLL multiplier value for crystal  .else  fosc    = ffrc  pllmul  =43            ;PLL multiplier value for internal fast RC oscillatot  .endif   fcy     = fosc*pllmul/plldiv/2  ; Calculated Fcy, Hz  mips    = fcy/1000000           ; Calculated MIPS   fclk    =fcy*2                ; Calculated peripheral clock frequency, Hz   baud    =38400                ; UART Baud rate  brgval  = (((fcy/baud)/16)-1)   ; Calculated UART BRG value   extref  =0            ; Set to 1 to configure ADC1 for external voltage reference   ;------------------------------------------------------------------------------  ; External connections to the ports:  ;------------------------------------------------------------------------------  ; Port aliases:  lcdport = LATD          ; Character SPI LCD port  leds    = LATD          ; LED port   ; Digital outputs:  d1      = RD0           ; LED1 (1 = ON)  d2      = RD1           ; LED2 (1 = ON)  d3      = RD2           ; LED3 (1 = ON)  d4      = RD3           ; LED4 (1 = ON)   lcdcs   = RD6           ; LCD CS line  lcdrs   = RD7           ; LCD RS line   ; Digital inputs:  ;sw1    = MCLR          ; SW1 (Reset)  sw2     = RB3           ; SW2 (0 = pressed)  sw3     = RB4           ; SW3 (0 = pressed)  sw4     = RB5           ; SW4 (0 = pressed)   ; Analog inputs:  pot1    = RB2  pot2    = RB1  temper  = RB0  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; X RAM Data  ;------------------------------------------------------------------------------  .data           ; RAM memory  foobuf:        .space  32      ; Example 32-byte buffer declaration  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; Flash Code & Data  ;------------------------------------------------------------------------------  .text           ; Program memory  ;------------------------------------------------------------------------------  ; Configuration Fuses  ;------------------------------------------------------------------------------  .ifdecl xtal  ; System clock setup for medium frequency xtal oscillator w/PLL:  ; System clock = primary osc w/PLL:        config  __FOSCSEL,FNOSC_PRIPLL  ; Clock switching and monitor disabled, OSC2 pin function = osc out, primary osc mode = XT:        config  __FOSC,FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMD_XT   .else  ; System clock setup for internal fast RC oscillator w/PLL:  ; System clock = internal fast RC osc w/PLL:        config  __FOSCSEL,FNOSC_FRCPLL  ; Clock switching and monitor disabled, OSC2 pin function = i/o port, primary osc disabled:        config  __FOSC,FCKSM_CSDCMD & OSCIOFNC_ON & POSCMD_NONE  .endif         config  __FWDT,FWDTEN_OFF       ; Watchdog timer disabled        config  __FICD,JTAGEN_OFF &ICS_PGD1    ; JTAG off, debugger pins = PGD1/PGC1        config  __FPOR,FPWRT_PWR1       ; Power on timer disabled  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; Main Code  ;------------------------------------------------------------------------------  __reset:        mov    #__SP_init,w15          ;Initalize the Stack Pointer        mov    #__SPLIM_init,w0        ; Initializethe Stack Pointer Limit Register        mov    w0,SPLIM               ; (__SP_init & __SPLIM_init values are calculated by linker)       nop                            ; Add NOP to follow SPLIM initialization         clr    PSVPAG                 ; Assume 32K limit for PSV space data access        clr    TBLPAG                 ; Assume 32K limit for code space data access        bset   CORCON,#PSV            ; Enable Program Space Visibility         rcall  init_osc               ; Set up oscillator        rcall  init_ports             ; Set up i/o ports        rcall  init_UART2             ; Set up UART2        rcall  init_timer1            ; Set up timer 1        rcall  init_timer3            ; Set up timer 3 (ADC timer)        rcall  init_ADC1              ; Set up ADC1        rcall  init_SPI2              ; Set up SPI2   ;------------------------------------------------------------------------------  ; Main program loop  main:        bra     main  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; Oscillator setup  init_osc:        mov     #pllmul-2,w0    ; Set PLL multiplier value        mov     w0,PLLFBD         clr    CLKDIV          ; Disableclock postscaler         mov     #OSCCON,w0      ; Prepare unlock values        mov.b   #0x46,w1        mov.b   #0x57,w2         mov.b  w1,[w0]         ; Unlock theOSCCON.L register        mov.b   w2,[w0]        bset.b  OSCCON,#LPOSCEN ; Enable secondary (32.768K) RTC oscillator         return  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; I/O ports setup  init_ports:         mov     #~((1<<pot1)|(1<<pot2)|(1<<temper)),w0        mov    w0,AD1PCFGL            ; Configure as analog input(s)  .ifdecl AD2PCFGL        mov    w0,AD2PCFGL            ; Same for 2nd ADC if present  .endif        mov    #(1<<pot1)|(1<<pot2)|(1<<temper)|(1<<sw2)|(1<<sw3)|(1<<sw4),w0        mov    w0,TRISB               ; Configure as digital input(s)         clr    TRISC                  ; Configure as digital output(s)        clr    TRISD                  ; Configure as digital output(s)        clr    TRISF                  ; Configure as digital output(s)        clr    TRISG                  ; Configure as digital output(s)         bset   CNPU1,#CN5PUE          ; Enable SW2 pullup        bset   CNPU1,#CN6PUE          ; Enable SW3 pullup        bset   CNPU1,#CN7PUE          ; Enable SW4 pullup         return  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; UART2 setup  init_UART2:        mov    #brgval,w0             ; Set Baudrate        mov    w0,U2BRG               ;         clr    U2STA                  ; Clear status/error flags         clr    U2MODE                 ; Enable UART for 8-bit data,        bset   U2MODE,#UARTEN          ;no parity, 1 STOP bit, no flow control, no wakeup         bset   U2STA,#UTXEN           ; Enable transmit, set TX int flag         mov    #(4<<U2RXIP0),w0        ; SetUART2 RX ISR IPL to 4        ior     IPC7         bclr   IFS1,#U2RXIF           ; Clear RX interrupt flag        bset   IEC1,#U2RXIE           ; Enable RX interrupts         return  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; Timer1 setup (128 Hz, free running, low power secondary 32768 Hz crystal osc clocked):  init_timer1:        mov    #0,w0          ; Forcefree running mode (no interrupt will be generated)        mov     w0,PR1         mov    #(1<<TON)|(1<<TCS)|(3<<TCKPS0),w0      ; Run Timer1 at 32768/256=128 Hz        mov     w0,T1CON         return  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; Timer3 setup (for ADC conversion start):  init_timer3:   t3_hz   = 15    ; Timer3 overflow rate, Hz         mov    #fcy/t3_hz/256,w0       ; Timer3 willoverflow t3hz times a second        mov    w0,PR3                 ;         mov    #(1<<TON)|(3<<TCKPS0),w0       ; Run Timer3 at Fin = Fcy/256        mov     w0,T3CON         return  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; ADC1 setup  init_ADC1:  ; 12 bit mode, integer data format, sync from timer3, auto sampling:        mov    #(1<<AD12B)|(0<<FORM0)|(2<<SSRC0)|(1<<ASAM),w0        mov     w0,AD1CON1   ; Selected Vref, one interrupt per every 3 conversions, autoscan:        mov     #(extref<<VCFG0)|(2<<SMPI0)|(1<<CSCNA),w0        mov     w0,AD1CON2   ; No ADRC (4 MHz) clock, 31 AD clocks per sample, 128 Tcy clocks per AD clock:        mov     #(0 << ADRC)|(31 << SAMC0)|(255 << ADCS0),w0        mov     w0,AD1CON3   ; Autoscan AN0, AN1, AN2 analog inputs:        mov     #(1<<RB0)|(1<<RB1)|(1<<RB2),w0        mov     w0,AD1CSSL   ; Set ADC1 ISR IPL to 4:        mov     #(4 << AD1IP0),w0        ior     IPC3         bclr   IFS0,#AD1IF            ; Clear ADC1 interrupt flag        bset   AD1CON1,#ADON          ; Turn on ADC and start conversions  ;       bset   IEC0,#AD1IE            ; Enable ADC interrupts         return  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; SPI2 setup:  init_SPI2:        mov    #(1<<MSTEN)|(7<<SPRE0)|(1<<PPRE0),w0   ; Master mode, Fsck1 = Fcy/16        mov     w0,SPI2CON1         bset   SPI2STAT,#SPIEN                ; Turn on SPI1         return  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; Delay for W0 usec:  delay_us:        repeat  #mips-4        nop         dec     w0,w0        bra     NZ,delay_us         return  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; ISRs  ;------------------------------------------------------------------------------  ; UART2 receive ISR:  __U2RXInterrupt:        push    w0         mov    U2RXREG,w0      ; Read a received byte fromUART2        mov     w0,U2TXREG      ; Send it back to PC         bclr   U2STA,#OERR     ; Clear the UART2 receive overrunflag (just for safety sake)        bclr    IFS1,#U2RXIF    ; Clear the UART2 receive interrupt flag         pop     w0        retfie  ;------------------------------------------------------------------------------   ;------------------------------------------------------------------------------  ; Constants in program memory  ;------------------------------------------------------------------------------   banner: .asciz  "PIC24HJ128GP206"   .end  `

post edited by DarioG - 2010/12/27 03:03:28

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
Relocatable Code Example by BitWise 2008/12/11 10:41:40 (permalink)
0
Relocatable Code Example by BitWise
http://forum.microchip.com/tm.aspx?m=389657

(rename attachment to "zip")
post edited by DarioG - 2010/12/27 03:03:08

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
Code to access DeviceID or IDLocations in C18 (all memory models): 2009/12/06 12:58:19 (permalink)
0
Code to access DeviceID or IDLocations in C18 (all memory models):

`      // ID LOCS  {        rom char far *pID=(rom char far *)0x200000;  // make this 0x3ffffe for Device ID         INTCONbits.GIE=0;        USBPCBuffO[2]=*pID++;        USBPCBuffO[3]=*pID++;        USBPCBuffO[4]=*pID++;        USBPCBuffO[5]=*pID;         TBLPTRU=0;            // sect. 3.1 C18 User's guide...        INTCONbits.GIE=1;  }`

post edited by DarioG - 2010/12/27 03:02:47

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
Generating a bit-reversal lookup-table on PIC16 and PIC18 ASM 2010/05/11 14:11:12 (permalink)
0
Generating a bit-reversal lookup-table on PIC16 and PIC18 ASM (by 1and0)
`   #define bitrev(i)   upper((((i) * 0x8020 & 0x88440) | ((i) * 0x0802 & 0x22110)) * 0x10101)    variable i  i = 0  while i <= 0xFF  retlw   bitrev(i)  i++  endw    variable i  i = 0  while i <= 0xFF  db      bitrev(i), bitrev(i+1)  i += 2`
endw
post edited by DarioG - 2010/12/27 03:01:37

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
Helper functions for converting UTC (SNTP) time into useful date/time structs: 2010/05/15 14:53:33 (permalink)
5 (3)
Helper functions for converting UTC (SNTP) time into useful date/time structs:

`  /* Following code:   * Copyright (c) 2007, LJCV Electronics. All Rights Reserved                  *   * San Antonio, Texas, USA. info@ljcv.net, www.ljcv.net                       *   *                                                                            *   *- Version Log --------------------------------------------------------------*   *   Date       Author        Comments                                        *   *----------------------------------------------------------------------------*   * 06/26/07 Jorge Amodio      Beta 0.9 test version                           *  //**************************************************************************** */    #ifdef MORE_TIME_STUFF   // Three character representation of month names  ROM char *month_str[] = {     "Jan", "Feb", "Mar", "Apr", "May", "Jun",    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"      };   // Three character representation of the day of the week  ROM char *wday_str[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };   // The following table is used to construct the string with different  // formats produced by asctime(), each group represents a time format  // that is composed by a sequence of 1 to 4 smaller character strings.  ROM char tformat[9][4] = {    { 1, 2, 3, 4 }, { 2, 3, 0, 0 }, { 3, 0, 0, 0 }, { 5, 0, 0, 0 },    { 3, 5, 0, 0 }, { 5, 3, 0, 0 }, { 6, 0, 0, 0 }, { 5, 6, 0, 0 },    { 6, 5, 0, 0 }      };   #endif   // Days on each month for regular and leap years  ROM char days_month[2][12] = {    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }      };   // isleap() takes the argument year and returns a non zero value if it is a  // leap year.   //  int isleap(int year) {    BYTE y;     y = (( year % 4 == 0 ) && ( year % 100 != 0 || year % 400 == 0 ));    return(y);      }   #ifdef MORE_TIME_STUFF  //*****************************************************************************  // mktime() take a tm time structure and generates the equivalent time_t  // value.  //  time_t mktime(tm *p) {    time_t j;    int i;     j = 0;     for(i=START_YEAR ; i < p->tm_year ; i++ ) {      j += isleap(i) ? 366 : 365;        }        for(i=0 ; i < p->tm_mon ; i++ ) {      j += days_month[isleap(p->tm_year)][i];        }         j = j + p->tm_mday - 1;    j *= 86400;      // convert to seconds     j = j + (time_t) (p->tm_hour * 3600L);    j = j + (time_t) (p->tm_min * 60L);    j = j + (time_t) (p->tm_sec);     return(j);      }  #endif   //*****************************************************************************  // offtime() takes a time_t value and generates the corresponding tm time  // structure taking in account leap years. It also takes an offset value  // as argument to facilitate correction for Time Zone and Day Light Savings  // Time.  //  void offtime(tm *ts, time_t t, long offset) {    long days, j;    int i, k;    char *p;     t += offset;                               // Correct for TZ/DST offset    days = t / 86400;                          // Integer number of days    j = t % 86400;                             // Fraction of a day    ts->tm_hour = j / 3600;                    // Integer number of hours    j %= 3600;                                 // Fraction of hour    ts->tm_min = j / 60;                       // Integer number of minutes    ts->tm_sec = j % 60;                       // Remainder seconds    ts->tm_wday = ( days + START_WDAY ) % 7;   // Day of the week     i = START_YEAR;     // Count the number of days per year taking in account leap years    // to determine the year number and remaining days    while(days >= (j = isleap(i) ? 366 : 365) ) {      i++;      days -= j;      }     while(days < 0) {      i--;      days += isleap(i) ? 366 : 365;      }     ts->tm_year = i;                           // We have the year      ts->tm_yday = days;                        // And the number of days     i = isleap(i);     // Count the days for each month in this year to determine the month    for(k=0; days >= days_month[i][k] ; ++k ) {      days -= days_month[i][k];      }     ts->tm_mon = k;                            // We have the month    ts->tm_mday = days + 1;                    // And the day of the month      }    #ifdef MORE_TIME_STUFF  //*****************************************************************************  // asctime() takes a tm time structure and converts the values into different  // character string formats. The seecond argument is a pointer to a character  // array that must be defined by the calling function with enough memory  // allocated to hold the resulting string, the string is terminated with the  // null (\0) character and does not contain CRLF (\n\r).  //  // The last argument specifies the desired output format for the string,  // current supported formats are:  //  //    0  DDD MMM dd HH:MM:SS YYYY  //    1  MMM dd HH:MM:SS  //    2  HH:MM:SS  //    3  mm/dd/yy  //    4  HH:MM:SS mm/dd/yy  //    5  mm/dd/yy HH:MM:SS  //    6  HH:MM  //    7  mm/dd/yy HH:MM  //    8  HH:MM mm/dd/yy  //  void asctime(tm *p, BYTE *q, BYTE format) {    BYTE i, j;     i = 0;     for(j=0 ; j < 4 ; j++ ) {      if(tformat[format][j] == 0 ) {            i--;            break;            }         switch(tformat[format][j]) {          case 1: // DDD                  memcpypgm2ram( &q[i], wday_str[p->tm_wday], 3);                  i += 3;                  break;                    case 2: // MMM dd                  memcpypgm2ram( &q[i], month_str[p->tm_mon], 3);                  i += 3;                  q[i++] = ' ';                  itoa(p->tm_mday,&q[i++]);                                    if ( p->tm_mday > 9 )                      i++;                                    break;                   case 3: // HH:MM:SS               if(p->tm_hour < 10 ) {                 q[i++] = '0';                 itoa(p->tm_hour, &q[i++]);                 }                else {                 itoa(p->tm_hour, &q[i]);                 i += 2;                 }               q[i++] = ':';                         if(p->tm_min < 10 ) {                q[i++] = '0';                 itoa(p->tm_min, &q[i++]);                 }                else {                 itoa(p->tm_min, &q[i]);                 i += 2;                 }               q[i++] = ':';                         if(p->tm_sec < 10 ) {                   q[i++] = '0';                   itoa(p->tm_sec, &q[i++]);                 }                else {                   itoa(p->tm_sec, &q[i]);                   i += 2;                 }               break;                   case 4: // YYYY               itoa(p->tm_year, &q[i]);               i += 4;               break;                   case 5: // mm/dd/yy               if ( p->tm_mon < 9 ) {                  q[i++] = '0';                 itoa(p->tm_mon + 1, &q[i++]);                 }                else {                 itoa(p->tm_mon + 1, &q[i]);                 i += 2;                   }               q[i++] = '/';                         if(p->tm_mday < 10 ) {                 q[i++] = '0';                 itoa(p->tm_mday, &q[i++]);                   }                else {                 itoa(p->tm_mday, &q[i]);                 i += 2;                   }                  q[i++] = '/';                      itoa(p->tm_year, &q[i]);                  memcpy((void *)&q[i], (void *)&q[i+2], 2);                  i += 2;                  q[i] = ' ';                  q[i+1] = ' ';                  break;                    case 6: // HH:MM            if ( p->tm_hour < 10 ) {              q[i++] = '0';              itoa(p->tm_hour, &q[i++]);              }             else {              itoa(p->tm_hour, &q[i]);              i += 2;              }            q[i++] = ':';                      if( p->tm_min < 10 ) {              q[i++] = '0';              itoa(p->tm_min, &q[i++]);              }             else {              itoa(p->tm_min, &q[i]);              i += 2;              }            break;          }       q[i++] = ' ';      }     q[i] = '\0';      }   #endif    `
post edited by DarioG - 2010/12/27 03:01:20

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
a detailed guide to building your own DC/DC converter using a little PIC, by Olin Lathrop 2010/10/26 04:10:08 (permalink)
0
a detailed guide to building your own DC/DC converter using a little PIC, by Olin Lathrop

http://www.microchip.com/forums/tm.aspx?m=450042
post edited by DarioG - 2010/12/27 02:56:58

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
A quick guide to Microchip USB Stack, by Tsuneo Chinzei 2010/12/27 02:56:40 (permalink)
0
So, I'm looking for a documentation, a tutorial or getting started guide that explain a little what are the different function like "USBDeviceTasks" and "ProcessIO".

Microchip has provided these documents for their USB device stack. Unfortunately, they are old ones. The stack has evolved further since those days. Almost 50% of their contents don't match to the current version.

MCHPFSUSB Firmware Userís Guide (2007)
http://ww1.microchip.com/...FSUSB_FW_UG_51679a.pdf

Microchip USB Device Firmware Framework Userís Guide (2008)
http://ww1.microchip.com/...n/DeviceDoc/51679b.pdf

Stack functions and callbacks of current version are briefly explained in this help file. However, it doesn't cover "USBDeviceTasks" and "ProcessIO"
C:\Microchip Solutions v2010-10-19\Microchip\Help\MCHPFSUSB Library Help.chm

OK, I'll give a brief explanation. (on the latest v2.8, v2010-10-19 version)

The source code of USBDeviceTasks() is placed in
C:\Microchip Solutions v2010-10-19\Microchip\USB\usb_device.c

This routine responds to register flags set by the USB engine (SIE: Serial Interface Engine) on PIC chip for these events. And it handles these events following to the USB spec.
a) USB Transactions
b) USB bus events

a) USB Transactions
On USB cable, Packets (SETUP, IN, OUT, DATA0, DATA1, ACK, NAK, STALL) are the unit of  USB communication. These Packets are tightly bound in sequence and timing, and they consist a Transaction (SETUP, IN, OUT). Every transaction is started by host. SIE processes Packets automatically. Just when a Transaction completes, it notifies to firmware by TRNIF bit. ie. for firmware, Transactions are the basic unit of USB communication.

Every Transaction has its target endpoint (EP).
On the default EP (EP0), Transactions are aligned in Control transfer protocol. Control transfer starts with SETUP Transaction, followed by IN or OUT Transaction(s) as DATA/STATUS stage. For every Transaction on EP0, USBDeviceTasks() should be called to move the state of Control transfer process.

By a Control transfer, a Request is carried. Standard Device Requests (Get_Descriptor, Set_Address, etc.) are mainly used for enumeration sequence. Class-specific Requests (HID:Get_Report, CDC:Set_Line_Coding) are defined for each USB Class. USBDeviceTasks() also processes these Requests almost internally. To modify stack default behavior, a couple of callbacks (USBCBInitEP(), etc) are placed on main.c of Microchip examples.

On EPs other than EP0, USBDeviceTasks() usually does nothing but flushing USTAT FIFO on the SIE. The Transactions for these endpoints are processed by your code in ProcessIO()(), using the stack routines like HIDTxHandleBusy(), HIDTxPacket(), etc.

b) USB bus events
Other than Transactions, USB cable carries these bus events to your device.
- Bus Reset
- Suspend/Resume
- SOF (Start Of Frame)
- Attach/Detach
SIE also notifies these events to firmware on register flags. USBDeviceTasks() processes (most of) required job for these events. To customize the stack default behavior, you may provide your code in the callbacks (USBCBSuspend(), etc) on main.c.

In above explanation, many USB terms appear. You'll find further explanation on these USB terms in these readings.

USB Made Simple - Part3 - Data Flow

USB in a NutShell - USB Protocols
http://www.beyondlogic.org/usbnutshell/usb3.shtml

USBDeviceTasks() is repeatedly called in main loop, when USB_POLLING is #define'd in usb_config.h
This routine moves to USB ISR (Interrupt Service Routine), when USB_INTERRUPT is #define'd instead of USB_POLLING
Microchip supposes you don't change this configuration at all.
main.c

`    #if defined(__18CXX)     void main(void)     #else     int main(void)     #endif     {            InitializeSystem();              #if defined(USB_INTERRUPT)             USBDeviceAttach();         #endif              while(1)         {             #if defined(USB_POLLING)             // Check bus status and service USB interrupts.             USBDeviceTasks(); // Interrupt or polling method.  If using polling, must call                               // this function periodically.  This function will take care                               // of processing and responding to SETUP transactions                                // (such as during the enumeration process when you first                               // plug in).  USB hosts require that USB devices should accept                               // and process SETUP packets in a timely fashion.  Therefore,                               // when using polling, this function should be called                                // regularly (such as once every 1.8ms or faster** [see                                // inline code comments in usb_device.c for explanation when                               // "or faster" applies])  In most cases, the USBDeviceTasks()                                // function does not take very long to execute (ex: <100                                // instruction cycles) before it returns.             #endif                                             // Application-specific tasks.             // Application related code may be added here, or in the ProcessIO() function.             ProcessIO();                 }//end while     }//end main    `

ProcessIO()
ProcessIO() is also repeatedly called in the main loop. Microchip expects majority of your custom code goes in this routine.
The contents of this routine is separated by (A) line, as follows.
`   void ProcessIO(void)     {            //         // Processes which don't use USB endpoint         //              // User Application USB tasks         if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;  // <--- (A)              //         // Processes which use USB endpoint         //     }    `

I would like a document that speak about the timing for the call of this function

As explained above, USBDeviceTasks() is called to process USB events notified by SIE.
The process deadline (time out) of each event is here.

USB Transactions on EP0
Around 100 us deadline when USB_PING_PONG__NO_PING_PONG is #define'd in usb_config.h
But it is relaxed to 50 ms for other ping-pong modes (FULL_PING_PONG, EP0_OUT_ONLY).
Therefore, you should not assign NO_PING_PONG

Bus Reset - 10 ms
Suspend - 7 ms (10ms - 3ms detection delay)
Resume - 20 ms
Attach - 100 ms

The calling interval (USB_POLLING) or interrupt latency (USB_INTERRUPT) is the minimum of these deadlines.
post edited by DarioG - 2010/12/27 02:59:47

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
proof of concept for using the EUSART in synchronous mode to generate 1KHz to 100 2011/11/02 15:09:25 (permalink)
0
Here is my proof of concept for using the EUSART in synchronous mode to generate both the 1KHz to 100KHz clock and the 120Hz to 12KHz clock. Is does work but the jitter between the two clock does not improve at lower frequencies.
(by Dan1138)

`           ;          ;   Filename:     main.asm       ;   Date:         2011-NOV-1       ;   Author:       dan1138       ;   Company:             ;                        ;   Files required: P18F4431.INC       ;                   18F4431_G.LKR generic linker script       ;          ;   Description:       ;          ;                  IFDEF __18F4520                      list P=18F4520, r=dec, n=0       #include "P18F4520.INC"                  ;   /* setup to use the 4xPLL with the 8MHz internal fast RC oscillator for a 32MHz system clock */                  ;              config OSC = INTIO67        ;/* Internal oscillator block, port function on RA6 and RA7          */           config FCMEN = OFF          ;/* Fail-Safe Clock Monitor disabled                                 */           config IESO = OFF           ;/* Oscillator Switchover mode disabled                              */           config PWRT = ON            ;/* PWRT enabled                                                     */           config BOREN = OFF          ;/* Brown-out Reset disabled in hardware and software                */           config BORV = 3             ;/* Brown-out voltage minimum setting                                */           config WDT = OFF            ;/* HW Disabled - SW Controlled                                      */           config WDTPS = 32768        ;/* 1:32768                                                          */           config CCP2MX = PORTC       ;/* CCP2 input/output is multiplexed with RC1                        */           config PBADEN = OFF         ;/* PORTB<4:0> pins are configured as digital I/O on Reset           */           config LPT1OSC = ON         ;/* Timer1 configured for low power operation                        */           config MCLRE = ON           ;/* MCLR pin enabled; RE3 input pin disabled                         */           config STVREN = OFF         ;/* Stack full/underflow will not cause Reset                        */           config LVP = OFF            ;/* Single-Supply ICSP disabled                                      */           config XINST = OFF          ;/* Instruction set extension and Indexed Addressing mode disabled   */                  ;   /* Turn off all code protection */           config CP0   = OFF, CP1   = OFF, CP2   = OFF, CP3   = OFF, CPB   = OFF           config WRT0  = OFF, WRT1  = OFF, WRT2  = OFF, WRT3  = OFF, WRTB  = OFF, WRTC  = OFF           config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF, EBTRB = OFF                  ;   /* Specify the System clock frequency in Hz */       #define FOSC 32000000                          ENDIF                          IFDEF __18F4431                      list P=18F4431, r=dec, n=0       #include <P18F4431.INC>                      ;   /* setup to use the 8MHz internal oscillator for system clock */                      config OSC = IRCIO          ;/* Internal oscillator block, port function on RA6 and RA7          */           config FCMEN = OFF          ;/* Fail-Safe Clock Monitor disabled                                 */           config IESO = ON            ;/* Oscillator Switchover mode enabled                               */           config PWRTEN = OFF         ;/* Power up timer enabled                                           */           config BOREN = OFF          ;/* Brown-out Reset disabled in hardware and software                */           config BORV = 27            ;/* VBOR set to 1.90 V nominal                                       */                                       ;           config WDTEN = OFF          ;/* Watch dog timer is always disabled. SWDTEN has no effect.        */           config WDPS = 32768         ;/* 1:32768                                                          */           config WINEN = OFF          ;/* WDT window disabled                                              */           config PWMPIN = OFF         ;/* PWM outputs disabled upon Reset (default)                        */           config LPOL = LOW           ;/* PWM0, 2, 4 and 6 are active-low                                  */           config HPOL = LOW           ;/* PWM1, 3, 5 and 7 are active-low                                  */           config T1OSCMX = OFF        ;/* Standard (legacy) Timer1 oscillator operation                    */           config FLTAMX = RC1         ;/* FLTA input is multiplexed with RC1                               */           config SSPMX = RC7          ;/* SCK/SCL clocks and SDA/SDI data are multiplexed with RC5 and RC4, respectively. SDO output is multiplexed with RC7. */           config PWM4MX = RB5         ;/* PWM4 output is multiplexed with RB5                              */           config EXCLKMX = RC3        ;/* TMR0/T5CKI external clock input is multiplexed with RC3          */           config MCLRE = ON           ;/* MCLR pin enabled; RE3 input pin disabled                         */           config STVREN = ON          ;/* Stack full/underflow will cause Reset                            */           config LVP = OFF            ;/* Single-Supply ICSP disabled                                      */       ;           ;   /* Turn off all code protection */           config CP0   = OFF, CP1   = OFF, CP2   = OFF, CP3   = OFF, CPB   = OFF, CPD   = OFF           config WRT0  = OFF, WRT1  = OFF, WRT2  = OFF, WRT3  = OFF, WRTB  = OFF, WRTC  = OFF, WRTD  = OFF           config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF, EBTRB = OFF                  ;   /* Specify the System clock frequency in Hz */       #define FOSC 8000000                          ENDIF                  ;   /* Specify the Peripheral clock frequency in Hz */       #define FCYC (FOSC/4)                  ;   Divisors for USART bit rate generator       #define CLK_100KHZ (FCYC/100000-1)       #define CLK_1KHZ (FCYC/1000-1)                  ; Put ISR context save storage in the ACCESS bank       INT_VAR         UDATA_ACS       W_TEMP          RES        1    ; w register for context saving (ACCESS)       STATUS_TEMP     RES        1    ; status used for context saving        BSR_TEMP        RES        1    ; bank select used for ISR context saving                  ;------------------------------------------------------------------------------       ; RESET VECTOR       ;------------------------------------------------------------------------------                  POR     CODE    0x0000          ; processor reset vector               GOTO    Main            ; go to IDATA initializer           movlw      R25T3_LENGTH                  ;------------------------------------------------------------------------------       ; HIGH PRIORITY INTERRUPT VECTOR       ;------------------------------------------------------------------------------                  ISRHV   CODE    0x0008               ; Run the High Priority Interrupt Service Routine               GOTO    HIGH_ISR                               ;------------------------------------------------------------------------------       ; LOW PRIORITY INTERRUPT VECTOR       ;------------------------------------------------------------------------------                  ISRLV   CODE    0x0018               ; Run the High Priority Interrupt Service Routine               GOTO    LOW_ISR                               ;------------------------------------------------------------------------------       ; HIGH PRIORITY INTERRUPT SERVICE ROUTINE       ;------------------------------------------------------------------------------                  ISRH    CODE                        ; let linker place high ISR routine                  HIGH_ISR:                      ; Insert High Priority ISR Here                      retfie  FAST                  ;------------------------------------------------------------------------------       ; LOW PRIORITY INTERRUPT SERVICE ROUTINE       ;------------------------------------------------------------------------------                  ISRL    CODE    ; let linker place low ISR routine                  LOW_ISR:           ; Context Saving for Low Priority ISR           MOVFF   STATUS, STATUS_TEMP ; save status register           MOVWF   W_TEMP              ; save W register           MOVFF   BSR, BSR_TEMP       ; save bankselect register                      ; Insert Low Priority ISR Here                      ; Restore Context for Low Priority ISR           MOVFF   BSR_TEMP, BSR       ; restore bank select register           MOVF    W_TEMP, W           ; restore W register           MOVFF   STATUS_TEMP, STATUS ; restore status register           RETFIE                  ;------------------------------------------------------------------------------       ; MAIN PROGRAM       ;------------------------------------------------------------------------------       ;        ;******************************************************************************                  ;******************************************************************************       ; Start of main program       ;          MAIN_DATA_ACCESS  UDATA_ACS       R25T3_INDEX res 1                  MAIN_CODE CODE              ; let linker place main program                  Main:            clrf    INTCON           bsf     RCON,IPEN       ;          ; Initialize PIC I/O pins       ;              IFDEF   __18F4520                      movlw   0x70                ; select internal 8MHz oscillator           movwf   OSCCON              ;           movlw   0x40                ; enable the 4xPLL           movwf   OSCTUNE                      ; Keep us happy by turning off the comparators           ; and letting their pins be digital I/O.           movlw   0x07                ; Turn off comparators           movwf   CMCON                      ; Keep simulator happy by initializing the ADC           ; Keep us happy by turning the ADC off.           movlw   0x02                ; Select internal RC as ADC clock source           movwf   ADCON2           movlw   0x0F                ; set all ADC inputs for digital I/O           movwf   ADCON1           movlw   0x00                ; Turn off ADC           movwf   ADCON0                      ENDIF                      IFDEF   __18F4431                      movlw   0x70                ; Set primary oscillator as system clock source           movwf   OSCCON,ACCESS       ; Use 8MHz internal oscillator                      MOVLW   0x00                ; Configure A/D           MOVWF   ANSEL0              ; for digital inputs           MOVWF   ANSEL1                      ENDIF                      CLRF    LATA                ; Initialize PORTA by clearing output data latches           MOVLW   0x00                ; Value used to initialize data direction           MOVWF   TRISA               ; Set RA<7:0> as outputs                          CLRF    LATB                ; Initialize PORTB by clearing output data latches           MOVLW   0x00                ; Value used to initialize data direction           MOVWF   TRISB               ; Set RB<7:0> as outputs                          CLRF    LATC                ; Initialize PORTC by clearing output data latches           MOVLW   0xC0                ; Value used to initialize data direction           MOVWF   TRISC               ; Set RC<7:0> as outputs                      ;          ; Test 100KHz and 12KHz ouput using synchronous USART TXD and TX clock       ;              movlw   B'00001000'         ; set for 16-bit BRG           movwf   BAUDCON            movlw   B'10110100'           movwf   TXSTA               ; enable synchronous TX           movlw   B'10000000'           movwf   RCSTA               ; enable serial port                      movlw   HIGH(CLK_100KHZ)    ; setup bit rate           movwf   SPBRGH           movlw   LOW(CLK_100KHZ)           movwf   SPBRG                      clrf    R25T3_INDEX                  ;***       Idle:           btfss   PIR1,TXIF           bra     Idle                      movlw   HIGH(R25T3)         ; send a sequence of           movwf   PCLATH              ; bit fields to cause           bcf     STATUS,C            ; the TXD line to toggle           rlcf    R25T3_INDEX,W       ; at a 25:3 ratio with           addlw   LOW(R25T3)          ; the TX clock output.           bnc     Idle2           incf    PCLATH,F       Idle2:           call    R25T3_LOOKUP           movwf   TXREG                      incf    R25T3_INDEX,F           movlw   R25T3_LENGTH           cpfslt  R25T3_INDEX           clrf    R25T3_INDEX           goto    Idle                  ;          ; TX clock to TXD 25:3 ratio       ; Note: Table must have less than 128 elements       ;          R25T3_LOOKUP:           movwf   PCL       R25T3:           dt  B'11110000'           dt  B'11110000'           dt  B'11110000'           dt  B'11100001'           dt  B'11100001'           dt  B'11000001'           dt  B'11000011'           dt  B'11000011'           dt  B'11000011'           dt  B'10000111'           dt  B'10000111'           dt  B'00000111'           dt  B'00001111'           dt  B'00001111'           dt  B'00001111'           dt  B'00011111'           dt  B'00011110'           dt  B'00011110'           dt  B'00111100'           dt  B'00111100'           dt  B'00111100'           dt  B'01111100'           dt  B'01111000'           dt  B'01111000'           dt  B'11110000'           dt  B'11110000'           dt  B'11110000'           dt  B'11110000'           dt  B'11100001'           dt  B'11100001'           dt  B'11000001'           dt  B'11000011'           dt  B'11000011'           dt  B'11000011'           dt  B'10000111'           dt  B'10000111'           dt  B'00000111'           dt  B'00001111'           dt  B'00001111'           dt  B'00001111'           dt  B'00011111'           dt  B'00011110'           dt  B'00011110'           dt  B'00111100'           dt  B'00111100'           dt  B'00111100'           dt  B'01111100'           dt  B'01111000'           dt  B'01111000'       R25T3_LENGTH equ    (\$-R25T3)/2                      end  `

post edited by DarioG - 2011/11/02 15:11:02

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
DDS in software on (old) PIC16, by JorgeF 2012/10/10 07:41:57 (permalink)
0
`                list p=PIC16C54C                      #include <p16c54c.inc>               ; ==== PIC configuration ====               __CONFIG   _CP_OFF & _WDT_OFF & _HS_OSC        ; External 20MHz crytal oscillator yelding an instruction cycle of 0.2 uS               ; ===== Definitions =======           ; ----- I/O ports ---------           ; register for port A (output) image due to R-M-W issue       PortImage        equ        0x08                   #ifdef __DEBUG       InputsPort        equ        0x09        ; Dummie register for MPLAB SIMulator debug               #else       ; Inputs port       InputsPort        equ        PORTB               #endif                   ; Outputs port       OutputsPort        equ        PORTA               ; ----- I/O bit maps ---------           ; Output pin in port A       OscilOutput        equ        RA0           ; freq select inputs in port B       SelFreq_1        equ        RB0       SelFreq_2        equ        RB1       SelFreq_3        equ        RB2       SelFreq_4        equ        RB3       SelFreq_5        equ        RB4               ; ===== Code ==============                   org 0x00               nop           clrf        PortImage        ; reset outputs image           clrf        OutputsPort        ; reset outputs                   #ifndef __DEBUG           ; Only for real hardware not used for MPLAB SIMulator           movlw        ((.1<<SelFreq_1)|(.1<<SelFreq_2)|(.1<<SelFreq_3)(.1<<SelFreq_4)|(.1<<SelFreq_5))           tris        InputsPort        ; Unused pin as outputs               #endif               movlw        0x00           tris        OutputsPort        ; all outputs               ; ******************************************************       ; The minimum step in instruction cycles for nested       ; loops is 2 so the intended cycle duratios of       ; 8, 9, 10, 11, 12, 13 instruction cycles must be splited        ; alternatelly in two groups         ;            ; ===== Code ==============           Loop1           nop           movlw        (.1<<OscilOutput)           xorwf        PortImage, F           movf        PortImage, W           movwf        OutputsPort       Loop1b           btfss        InputsPort, SelFreq_1        ; 310 (312.5) KHz           goto        Loop1                        ; 8 instruction cycles - Inputs: 0x00               btfss        InputsPort, SelFreq_2        ; 250 (250) KHz           goto        Loop1                        ; 10 instruction cycles    - Inputs: 0x01               btfss        InputsPort, SelFreq_3        ; 210 (208.33) KHz           goto        Loop1                        ; 12 instruction cycles    - Inputs: 0x03           goto        Loop2b           Loop2           btfss        InputsPort, SelFreq_3        ; get back to first loop (even cycles)           goto        Loop1b           movlw        (.1<<OscilOutput)           xorwf        PortImage, F           movf        PortImage, W           movwf        OutputsPort       Loop2b           btfss        InputsPort, SelFreq_4        ; 280 (277.78) KHz            goto        Loop2                        ; 9  instruction cycles    - Inputs: 0x07               btfss        InputsPort, SelFreq_5        ; 225 (227.27) KHz            goto        Loop2                        ; 11 instruction cycles    - Inputs: 0x0f               nop           goto        Loop2                        ; 190 (192.31) KHz                                                   ; 13 instruction cycles    - Inputs: 0x1f               END       `

http://www.microchip.com/forums/fb.ashx?m=680759
post edited by DarioG - 2012/10/10 07:43:03

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
Slave I2C in Software 2013/01/15 15:51:55 (permalink)
0
(code derived from some AN I found many many years ago...! Used quite often with success, and also ported to C: assembler @20MHz and C @40MHz)

` ; obvious defines :) this implementation used RC6-7TCREAD        EQU    11111001b                     ;TRIS register for SDA readTCWRITED    EQU    01111001b                   ;TRIS register for SDA writeTCWRITEC    EQU    10111001b                   ;TRIS register for SCL write (wait)PCINIT   EQU  00011000b                            ;verificare su I2C hardware!!   TCINIT        EQU    TCREAD                           ;Initial TRIS value (PORTC)   I2CCIBit    equ 6        ; Clock I2CI2CDBit        equ 7        ; Dati I2CI2CCIVal    equ 1 << I2CCIBitI2CDVal        equ 1 << I2CDBit     ; this part of code implements handling of incoming (writes) and outgoing (reads) commands...   recvMsg:   #ifdef I2C_SMBUS       movlw  I2CR0+1   #else       movlw  I2CR0   #endif       movwf  FSR       movlw        high recvMsgTable        ; serve davvero?? sÿì!       movwf        PCLATH       movfw   I2CSUBA           ;switch()       andlw        0fh       addwf        PCL, f                ;Add offset       if (high recvMsgTable != high (recvMsgTableHigh))           ERROR    "Table crosses memory boundary"     endif    recvMsgTable:       goto        recvMsg_cls       goto        recvMsg_setXY       goto        recvMsg_print       goto        recvMsg_vScroll            ; cambiare ?       goto        recvMsg_setClock       goto        recvMsg_setLight_Clock_Buzz       goto        recvMsg_setLed       goto        recvMsg_unused     recvMsgTableHigh:    recvMsg_cls:       goto LCDCls           recvMsg_setXY:     return       recvMsg_print:    #ifdef I2C_SMBUS       decf  I2CCNT,w       movwf  temp2   #else       movfw  I2CCNT       movwf  temp2   #endif       goto   LCDWriteN     recvMsg_vScroll:       goto  LCDScrollDown     recvMsg_setLight_Clock_Buzz:   #ifdef I2C_SMBUS       btfsc   I2CCNT,2                ; qui devono essere proprio 5        btfss   I2CCNT,0   #else       btfss   I2CCNT,2                ; qui devono essere proprio 4   #endif       return    ;    movfw        I2CR0            ; qui ci sarebbe il cnt.byte (in modalita' BLOCK_WRITE SmBus)       movfw INDF       bz  noLuceSet        btfsc INDF,7                ; b7=fading       bsf  FLAGS,FADEON        addlw -1                                ; 1..16       andlw 0xf       movwf LuceLCD       movfw FSR                    ; salvo FSR per EEprom...       movwf temp2       movlw LuceLCD       call EEcopiaAEEPROM       movfw temp2       movwf FSR   noLuceSet:        incf FSR,f       movfw INDF       bz  noContrSet       addlw -1                                ; 1..16       andlw 0xf       movwf ContrLCD                   movfw FSR                    ; salvo FSR per EEprom...       movwf temp2       movlw ContrLCD       call EEcopiaAEEPROM       movfw temp2       movwf FSR   noContrSet:        incf FSR,f       btfsc INDF,0       bsf  FLAGS2,CLOCK_ON       btfss INDF,0       bcf  FLAGS2,CLOCK_ON       btfsc INDF,1       bsf  FLAGS2,BIG_CLOCK_ON       btfss INDF,1       bcf  FLAGS2,BIG_CLOCK_ON       btfsc INDF,4                                    ;1=no! (per lasciare default=sÿì...)       bsf  FLAGS,NOKCLICK       btfss INDF,4       bcf  FLAGS,NOKCLICK        incf FSR,f       movfw INDF       bz  noFreqSet       sublw 32-1                    ; minimo 32 (v. PWM luce) (circa 10KHz per buzzer)       movfw INDF       btfsc STATUS,C       movlw 32       movwf BeepFreq     return        recvMsg_setLed:   #ifdef I2C_SMBUS   ;    movfw        I2CR0            ; qui ci sarebbe il cnt.byte (in modalita' BLOCK_WRITE SmBus)       incf  FSR,f   #else   #endif       movfw     INDF       movwf  PORTE   recvMsg_unused:       retlw 0    recvMsg_setClock:   ;#IFDEF __16F874                    ; altrimenti dare errore?? NO, uso Flash ext!   #ifdef I2C_SMBUS       bsf STATUS,RP0                    ; per I2CR0   ;    movfw        I2CR0            ; qui ci sarebbe il cnt.byte (in modalita' BLOCK_WRITE SmBus)       movlw  Clock_S       movwf  FSR       movfw    I2CR0+1       call  EEscrivi       incf  FSR,f       movfw    I2CR0+2       call  EEscrivi       incf  FSR,f       movfw    I2CR0+3       call  EEscrivi       incf  FSR,f       movfw    I2CR0+4       call  EEscrivi       incf  FSR,f       movfw    I2CR0+5       call  EEscrivi       incf  FSR,f       movfw    I2CR0+6       call  EEscrivi       bcf STATUS,RP0   #else       bsf STATUS,RP0                    ; per I2CR0       movlw  Clock_S       movwf  FSR       movfw    I2CR0       call  EEscrivi       incf  FSR,f       movfw    I2CR0+1       call  EEscrivi       incf  FSR,f       movfw    I2CR0+2       call  EEscrivi       incf  FSR,f       movfw    I2CR0+3       call  EEscrivi       incf  FSR,f       movfw    I2CR0+4       call  EEscrivi       incf  FSR,f       movfw    I2CR0+5       call  EEscrivi       bcf STATUS,RP0   #endif        clrf  Clock_10       retlw 0      ; ---------------------------------------------------------------------------------   sendMsg:       movlw        high sendMsgTable       movwf        PCLATH       movfw   I2CSUBA          ;switch()       andlw        03h       addwf        PCL, f                ;Add offset      if (high sendMsgTable != high sendMsgTableHigh)           ERROR    "Table crosses memory boundary"     endif    sendMsgTable:       goto        sendMsg_getID       goto        sendMsg_getCfg       goto        sendMsg_getCfg2       goto        sendMsg_readFlash   sendMsgTableHigh:     sendMsg_getID:    ;**********************************************************************   ;* Device ID Table (must be at start - OCCHIO a ADDWF PCL,F)   ;* TABLE FOR UNIT ID returns next char in W   ;**********************************************************************   GETID:       MOVFW   I2CCNT            ;W=I2CCNT       ANDLW   07H             ;Limit to 8 locations       ADDWF   PCL,F    ;**********************************************************************   ;* Device ID text: read starting at sub-address 0   ;**********************************************************************       dt  "ADPMLCD", (VERNUMH << 4) | VERNUML    sendMsg_getCfg:                        ; v. anche QUERY_STATUS per 232!       MOVFW   I2CCNT          ;byte count       ANDLW    3                                ;0..3 (2 dim.LCD + 2 pos. cursore)       addlw   LCDCols                    ;Offset from buffer start       MOVWF   FSR             ;Indirect address       MOVFW   INDF            ;Get data from register       return    sendMsg_getCfg2:                    ; v. anche QUERY_STATUS per 232!       MOVFW   I2CCNT            ;W=I2CCNT       ANDLW   03H             ;Limit to 4 locations (GET_EQUIPMENT)       ADDWF   PCL,F       retlw 1       retlw 2       retlw 0       retlw 0        return   ; from here onward, the actual tight loop that manages the communication with the Master; this has to be called quite often (say <10uS in order to meet the 100KHz clock frequency), then the actual command may take more by mean of clock-stretching)   ;************************************************************  ; Main wait loop while idle. POLL loop should be called here  ;************************************************************   I2CWAIT:      clrf I2CFLG                    ;Init state flags      clrf I2CCNT      ; I2CSUBA viene pulito solo in seguito a uno stop, in modo che la BLOCK_READ (che usa uno start-ripetuto) puo' "riciclarlo" piu' volte...      bsf  INTCON,GIE                                ; riabilito tutti gli interrupt  ;    bcf FLAGS,NOSCANK                            ; oppure basta questo...?   loop1:      CLRWDT                  ;Clear watchdog timer (senza prescaler => tWDT=18mSec)       call doMain                            ;Call user code while in idle state       btfsc PORTC,I2CDBit            ;Wait for SDA&SCL=H  loop2:      btfss PORTC,I2CCIBit            ;      GOTO  loop1                            ; No longer valid to wait for start!       CLRWDT                  ;Clear watchdog timer       call doMain                            ;Call user code while in idle state   ;** wait for start **      btfsc PORTC,I2CCIBit        ;Clock has dropped, niente.      btfsc PORTC,I2CDBit            ;Se invece data dropped con CLK=1... Start!      GOTO  loop2   I2CRESTART:       bcf  INTCON,GIE                                ; disabilito tutti gli interrupt       clrf I2CFLG                    ;Init state flags  ;** START RECEIVED! --- wait for first bit!  loop3:      btfsc    PORTC,I2CDBit      goto I2CWAIT                        ;Data raised before clock dropped -- abort      btfsc PORTC,I2CCIBit      goto loop3                            ;Wait for clock low    NEXTBYTE:  ; ********* mettere TIME-OUT in caso la comunicazione non terminasse correttamente!!       CLRWDT                  ;Clear watchdog timer      MOVLW   1               ;Init receive byte so bit falls off at end!      MOVWF   I2CREG   ;** Shift bits! -- external poll may be executed during low clock cycle only!  ;* ENABLE line is checked for loss of enable ONLY during HIGH CLOCK   ;*** CLOCK IS LOW -- DATA MAY CHANGE HERE  ;*** We have at least 4us before any change can occur   loop4:  loop4A:      CLRWDT      btfss PORTC,I2CCIBit      goto    loop4A                            ;Wait for clock high   ;*** CLOCK IS HIGH -- SHIFT BIT - then watch for change      RLF     PORTC,W                    ;Move RC7 (data) into C      RLF     I2CREG,F        ;Shift in bit       SKPNC                                    ;Skip if not done      GOTO    ACK_I2C         ;Acknowledge byte       BTFSC   I2CREG,0        ;Skip if data bit was 0      GOTO    ii_1            ;This bit was set  ii_0:      btfss PORTC,I2CCIBit      goto  loop4                            ;Wait for clock low      btfss PORTC,I2CDBit            ;Data low-high == stop      GOTO    ii_0   I2CSTOP:         MOVLW   TCWRITEC                ; wait state      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0      call  recvMsg           ; process completed message! (ricevuto STOP, fine byte ricevuti, processo il gruppo di byte ricevuti)      pagesel recvMsg                    ; riaggiusta PCLATH in caso da recvMsg fosse andato nel bank 1      MOVLW   TCINIT      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0      clrf  I2CSUBA                        ; pulisco subaddr...      GOTO    I2CWAIT         ;back to main loop   ii_1:      CLRWDT      btfss PORTC,I2CDBit      goto  I2CRESTART                    ;Data high-low (a meta' ricezione) == re-start      btfss PORTC,I2CCIBit      goto  loop4                            ;Wait for clock low      GOTO  ii_1   ACK_I2C:      btfss    I2CFLG,B_UA      goto  ACK_UA                            ;Not addressed - check unit address      btfsc I2CFLG,B_SA      goto  ACK_SA                            ;Reading secondary address   ;****  ;** Do what must be done with new data bytes here (before ACKloop)  ;** Don't ack if byte can't be processed!  ;****  ;--------       ;USER_RECV                            ; qua ci passo byte per byte, dopo i primi 2 (address e subaddress)      btfsc   I2CCNT,3                ; devono essere max 8 (0..7) ...      goto        I2CWAIT                    ; ...altrimenti non-ACK      movlw   I2CR0           ; mi posiziono nel buffer      addwf        I2CCNT,w                ; guardo quanti byte ho gia' usato      INCF    I2CCNT,F                ;Next position      MOVWF   FSR             ;Indirect address      MOVFW   I2CREG      MOVWF   INDF            ;Put data into register   IN_CONT:                  ;continue point for intercepted bytes (non usato)   ACKloop:      CLRWDT      btfsc PORTC,I2CCIBit      goto  ACKloop                        ;Wait for clock low       MOVLW   TCWRITED                ; Set ACK (=0)      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0   ACKloop2:      CLRWDT      btfss PORTC,I2CCIBit      goto ACKloop2                        ;Wait for clock high   ACKloop3:      CLRWDT      btfsc PORTC,I2CCIBit      goto ACKloop3                        ;Wait for clock low       MOVLW  TCINIT             ;End ACK      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0   ;    nop    ; NO qui non serve altro ritardo!        btfss I2CFLG,B_RD                ; se sono in lettura, vado a spedirgli i byte...      goto NEXTBYTE                        ;   (altrimenti continuo a ricevere)   normalRead:                  #ifdef I2C_SMBUS                    ; (se in SmBus)...e comincio indicando 4/8 byte da ricevere all'host      movlw 8                                    ; 8 byte per comando 0...      movf    I2CSUBA,f      btfss STATUS,Z      movlw 4                                    ; ...e 4 per gli altri      goto  OUT_CONT  #else      call  sendMsg                        ; (altrimenti NON metto il # byte all'inizio!)      INCF    I2CCNT,F        ;Next byte      goto  OUT_CONT  #endif    ;*********************************************************************  ; I2C Readback (I2C read request)  ; Application specific code to get bytes to send may be added here.  ; This routine gets data from location pointed to by I2CSUBA and  ; sends it to I2C. Subsequent reads get sequential addresses. This version  ; AND's the register # with 7 to limit to 8 registers (for speed). This  ; could be modified to do a comparison to an absolute number.  ;  ;*********************************************************************   NEXTOUT:   ;*** <<< PUT NEXT BYTE INTO I2CREG HERE NOW! >>> ***      MOVFW   I2CREG    OUT_CONT:      MOVWF   I2CREG  ;-- add code here to init I2CREG! when B_ID is clear!    boh?      MOVLW   8               ;Bit counter      MOVWF   I2CBITS   ;** OUT bits! -- external poll may be executed during low clock cycle, but  ;                may also be executed during high cycle if necessary.   ;* ENABLE line is checked for loss of enable ONLY during HIGH CLOCK   ;*** CLOCK IS LOW -- CHANGE DATA HERE FIRST!   ;*** loop 1: data was 1  iiOUT_loop_1:      RLF     I2CREG,F        ;Shift data out, MSB first      SKPNC                                    ;1->0: change      GOTO    iiOUT_1         ;Output another 1!      MOVLW   TCWRITED                ; output 0      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0   iiOUT_0:   iiOUT_loop_02:      CLRWDT                  ;Clear watchdog timer      btfss PORTC,I2CCIBit      goto iiOUT_loop_02            ;Wait for clock high   iiOUT_loop_03:      CLRWDT      btfsc PORTC,I2CCIBit      goto iiOUT_loop_03            ;Wait for clock low       DECFSZ  I2CBITS, F      ;Count bits      GOTO    iiOUT_loop_0    ;Loop for last bit 0      MOVLW  TCINIT           ;Done with last bit 0... Set to 1 for ACK      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0  ;    nop      nop      nop       GOTO    iiOUT_ack       ;Get ACK   iiOUT_loop_0:      RLF     I2CREG,F        ;Shift data out, MSB first      SKPC                                  ;0->1: change      GOTO    iiOUT_0         ;Output another 0!       MOVLW  TCINIT             ;Set to 1      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0  ;    nop      nop      nop    iiOUT_1:      CLRWDT                  ;Clear watchdog timer   iiOUT_loop_12:      CLRWDT      btfss PORTC,I2CCIBit      goto    iiOUT_loop_12            ;Wait for clock high   iiOUT_loop_13:      CLRWDT      btfsc PORTC,I2CCIBit      goto    iiOUT_loop_13            ;Wait for clock low       DECFSZ  I2CBITS, F      ;Count bits      GOTO    iiOUT_loop_1    ;Loop for last bit 1    iiOUT_ack:                                ;Get acknowledge   iiOUT_loop_a2:      CLRWDT      btfss PORTC,I2CCIBit      goto  iiOUT_loop_a2            ;Wait for clock high       btfsc PORTC,I2CDBit      goto    I2CWAIT                        ;No ACK --- wait for restart!   ;-- prepare next character here!      MOVLW   TCWRITEC                ; wait state      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0      call  sendMsg       MOVWF   I2CREG      MOVLW  TCINIT      bsf        STATUS,RP0                ; bank 1      movwf    TRISC      bcf        STATUS,RP0                ; bank 0      INCF    I2CCNT,F        ;Next byte   iiOUT_loop_a3_:      CLRWDT      btfss PORTC,I2CCIBit      goto    iiOUT_loop_a3            ;Wait for clock low...       btfss PORTC,I2CDBit      goto    iiOUT_loop_a3_        ; ...e che termini ACK    iiOUT_loop_a3:      CLRWDT      btfss PORTC,I2CCIBit      goto    NEXTOUT                        ;Wait for clock low - output next char!       btfsc PORTC,I2CDBit      goto    iiOUT_loop_a3            ;Watch out for new start condition!      clrf  I2CSUBA                        ; pulisco subaddr...      GOTO  I2CWAIT                        ;Stop received!   ;    USER_READ                 ;user code to process data sent   ;    GOTO  I2CWAIT    ;**********************************************************************  ;* Unit address received - check for valid address  ;*  ;**********************************************************************  ACK_UA:      bsf            I2CFLG,B_UA            ;Flag unit address received      BTFSC   I2CREG,0        ;Skip if data coming in      bsf            I2CFLG,B_RD            ;Flag - reading from slave      MOVFW   I2CREG            ;Get address      ANDLW   0FEH            ;Mask direction flage before compare      XORLW   DEVICE_ADDRESS  ;Device address      BNZ     I2CWAIT         ;Not for me! (skip rest of message)      btfsc        I2CFLG,B_RD      goto        ACKloop                    ;Read - no secondary address      bsf            I2CFLG,B_SA            ;Next is secondary address      GOTO    ACKloop         ;Yes! ACK address and continue!   ;**********************************************************************  ;* Secondary address received - stow it!  ;**********************************************************************  ACK_SA:      bcf            I2CFLG,B_SA            ;Flag second address received      MOVFW   I2CREG          ;Get subaddress      MOVWF   I2CSUBA         ;Set subaddress      GOTO    ACKloop    doMain:       `

Note that some (basic) handling of SMBus was also tried.
post edited by DarioG - 2013/01/15 15:57:30

GENOVA :D :D ! GODO
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
Re:Slave I2C in Software 2013/01/18 05:34:33 (permalink)
0
And, due to more requests , here it goes the C version:

(stupid forum won't let me post the code, it is attached...)

Similar restriction and considerations about timing and ports used apply.
post edited by DarioG - 2013/01/18 05:35:51

GENOVA :D :D ! GODO
AbuSaleh
New Member
• Total Posts : 3
• Reward points : 0
• Joined: 2012/12/13 15:12:35
• Location: 0
• Status: offline
Re:Code for sending int/floats as raw binary data (chars) to USART 2013/01/24 15:00:18 (permalink)
0
Thank you for reply, but this is for sending one float. How to send 4 floats simultaneously ?
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
SW UART in C (C18; only TX) 2013/02/03 06:00:15 (permalink)
0
` #include <p18cxxx.h>#include <typedefs.h>#include "sw_uart.h"/************************************************;*      SUBROUTINE TO SEND A BYTE               *;*      AS RS232C FORMAT 8,N,1                  *;************************************************/void putcUART(byte Data_AREA) {    byte COUNT;    INTCONbits.GIE=0;#ifndef BIT_7_MODE    COUNT=8;             //RESET 8 BIT COUNT#else    COUNT=7;                // reset 7 bit count#endif#ifdef TX_BUFFERED    m_TXBit=0;               //LOW RD FOR START BIT#else    m_TXBit=1;            //High RD FOR START BIT#endif    BitWork();    do {        if(Data_AREA & 1) {        //0 / 1 ?#ifdef TX_BUFFERED            m_TXBit=1;            //SEND A 1#else            m_TXBit=0;            //SEND A 1#endif            }        else {#ifdef TX_BUFFERED            m_TXBit=0;                //SEND A 0#else            m_TXBit=1;                //SEND A 0#endif            }        Data_AREA >>= 1;       //SHIFT Data TO CARRY        BitWork();        } while(--COUNT);          //COUNT = ?#ifdef TX_BUFFERED    m_TXBit=1;                //SEND STOP BIT#else    m_TXBit=0;                //SEND STOP BIT#endif    BitWork();/* boh, no#ifdef TX_BUFFERED    m_TXBit=1;                //SEND STOP BIT (un altro...)#else    m_TXBit=0;                //SEND STOP BIT (un altro...)#endif    BitWork();*/    INTCONbits.GIE=1;    }void putsUART(char *s) {    while(*s)        putcUART(*s++);    }void putrsUART(const rom char *s) {    while(*s)        putcUART(*s++);    }`

This is include file sw_uart.h
` #undef TX_BUFFERED#define BAUD_TIME 52#define BitWork() Delay_uS(BAUD_TIME-9)        //19200baudvoid putcUART(byte );void putsUART(char *);void putrsUART(const rom char *); #define m_TXBit LATCbits.LATC5        //boh, a caso, solo x debug `

GENOVA :D :D ! GODO
odalcet
New Member
• Total Posts : 14
• Reward points : 0
• Joined: 2012/07/15 04:21:09
• Location: 0
• Status: offline
Re:Working CONFIG settings for 18F2550/4550 2013/03/18 13:16:57 (permalink)
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
Re:Working CONFIG settings for 18F2550/4550 2013/03/18 14:16:48 (permalink)
0
Hmm yeah... a pity, it was not mine !

GENOVA :D :D ! GODO
Ian.M
Super Member
• Total Posts : 13273
• Reward points : 0
• Joined: 2009/07/23 07:02:40
• Location: UK
• Status: offline
Re:Working CONFIG settings for 18F2550/4550 2013/03/18 14:42:03 (permalink)
DarioG
Allmächtig.
• Total Posts : 54081
• Reward points : 0
• Joined: 2006/02/25 08:58:22
• Location: Oesterreich
• Status: offline
Re:Working CONFIG settings for 18F2550/4550 2013/03/19 02:13:52 (permalink)
0
wow thanks!
(not that it adds any special info to what is already in the datasheet, but... )

GENOVA :D :D ! GODO
Page: < 123 > Showing page 2 of 3