Maximum frequency output from a PIC


Closed Thread
Results 1 to 40 of 69

Hybrid View

  1. #1
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    Hi,

    Robert,
    Yes, the 16F727 has its program memory divided into four pages so I can see it making a difference on that one. But still, I'm not cyet onvinced that having them "first" is what actually helps, I believe it's more like where they (the subroutines that is) are relative to where the calls TO them are. I mean, calling subroutines in page 0 from Main in page 1 should be no different from calling subroutines in page 1 from Main in page 0....it needs to switch page in both cases.

    Darrel or anyone - are you listening? Care to share some details?

    Art,
    If that interpreted BASIC, whichever it is, really works like that it kind of sucks - big time IMO.
    As for the rest, you're now talking about RAM and not program memory.

    /Henrik.

  2. #2
    Join Date
    Jan 2009
    Location
    Miami, Florida USA
    Posts
    699


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    Yes, unfortunately I don't know the facts either. It would be good if somebody else clarifies this point here.
    "No one is completely worthless. They can always serve as a bad example."

    Anonymous

  3. #3
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    I've posted a question on the MELABS support forum. Hopefully Darrel or someone else will give us some insight.

    /Henrik.

  4. #4
    Join Date
    Aug 2003
    Posts
    985


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    Quote Originally Posted by HenrikOlsson View Post
    Hi,
    Art,
    If that interpreted BASIC, whichever it is, really works like that it kind of sucks - big time IMO.
    As for the rest, you're now talking about RAM and not program memory.

    /Henrik.

    The second part is in relation to the link posted (keeping vars in BANK0 - avoiding switch statements).

    I will try to explain why it is important to put code you want to run fast at the beginning of your PBP program,
    even though I was incorrect as to one of the reasons why, there are more, and PBP actually does this in the
    compiled assembler program (with it's own function calls, not yours) whether you like it or not.

    You want to keep most called functions (PBP routines) in the first 2K code space to avoid page switching.
    You also want to keep most used variables in Bank0 to avoid bank switching (for RAM).

    Say you fill up the first 2K page with code, and run into the second code page,
    then introduce a serin or serout command in the second code page.
    PBP doesn't put the serin command where you wrote it.
    Every PBP macro command such as serial is placed at the beginning of the generated
    assembler code, which kicks some of your your PBP code out of the first 2K code space.
    What is placed where you wrote the serial command is a series of gosubs that pass
    individual bytes to the assembler routine which has been placed at the beginning of the asm source.

    You wil notice that if you use a second serial command, your code size doesn't massively increase again
    because the original asm routine that was inserted by the first serial command is reused.

    When you use a serin, and serout command, this is the decompiled assembler that is placed
    at the beginning of your compiled code to deal with it:
    Code:
    SerialIN							;receive serial byte with pre-determined timeout
      movf		R6		,W				;move timeout delay to temp
      movwf		R0						;
      movf		R15		,W				;
      movwf		R9						;
      movlw		0x01						;
      movwf		R1						;set inside loop counter
      clrf		R10						;
    serial_loop							;
      clrwdt							;keep watchdog timer clear
      call		SerinX						;get one bit
      btfss		status		,C				;wait for start bit
      goto		serinstart					;
      decfsz	R1		,F				;
      goto		serial_loop					;
      movlw		0xFF						;
      addwf		R10		,F				;
      btfsc		status		,C				;
      goto		serial_loop					;
      addwf		R0		,F				;
      btfss		status		,C				;
      addwf		R9		,F				;
      btfss		status		,C				;
      goto		DoneX						;time out
      movlw		0x32						;
      movwf		R1						;reset inside loop counter
      clrw								;
      movwf		R10						;
      goto		serial_loop					;
    SerialIN_notimeout						;
      clrwdt							;receive byte serialy with no timeout
      call		SerinX						;get one bit
      btfsc		status		,C				;wait for start bit
      goto		SerialIN_notimeout				;
    serinstart							;
      call		serialdelay					;wait 1/4 bit time
      clrf		R4						;zero parity accumulator
      movlw		0x08						;number of bits in one byte
      movwf		R10						;
    serpar								;
      call		seroutdelay					;wait bit time
      call		SerinX						;get one bit
      btfsc		status		,C				;accumulate parity
      incf		R4		,F				;
      btfss		R14		,05				;if no parity...
      clrf		R4						;...keep it even
      rrf		R1		,F				;move bit into byte
      decfsz	R10		,F				;check for more bits
      goto		serpar						;
      btfsc		R14		,05				;if parity...
      bcf		R1		,07				;...clear top bit of result
      call		seroutdelay					;delay to stop bit
      bsf		status		,C				;carry shifts in clear
      movf		R1		,W				;get char to W
      return							;
    SerinX								;
      movf		RR2		,W				;receive one bit for serial in
      movwf		fsr						;
      movf		RR1		,W				;
      bsf		fsr		,07				;
      iorwf		indf		,F				;
      bcf		fsr		,07				;
      andwf		indf		,W				;
      btfsc		R14		,06				;
      xorwf		RR1		,W				;
      addlw		0xFF						;
      return							;
    SerialIN_skipbyte						;
      movf		R13		,W				;ignore received byte for serial in
      bsf		status		,C				;
      btfsc		status		,Z				;
      goto		DoneX						;
      call		skipX						;
      btfss		status		,C				;
      return							;
      decf		R13		,F				;
      goto		SerialIN_skipbyte				;
    
    serialOUT							;transmit byte serialy from port pin
      movwf		R3						;save byte to send
      movf		RR2		,W				;get port to fsr
      movwf		fsr						;
      movlw		0x80						;zero parity accumulator (preserve blanking)
      andwf		RM2		,F				;
      movlw		0x08						;1 start bit + 7 data bits
      movwf		R12						;
      bcf		status		,C				;start bit low
    seroutloop							;
      btfsc		status		,C				;accumulate parity bits
      incf		RM2		,F				;
      call		seroutbit					;send a bit and delay bit time
      rrf		R3		,F				;move to next bit
      decfsz	R12		,F				;do next bit, if any
      goto		seroutloop					;
      nop								;
      btfsc		R14		,05				;send parity
      rrf		RM2		,W				;get parity to carry
      call		seroutbit					;send parity or last bit and delay bit time
      call		Done						;
      bsf		status		,C				;stop bit high
      call		seroutbit					;send stop bit and delay bit time
      movf		R16		,W				;do pacing
      movwf		R10						;
      movf		R7		,W 				;
      goto		DelayX						;
    seroutbit							;
      bcf		fsr		,07				;make sure we're pointing to the port
      btfss		R14		,07				;check for TRIS mode
      goto		seroutnorm					;handle normal mode
      movf		indf		,W				;get port data
      iorwf		RR1		,W				;set bit on
      btfss		R14		,06				;bit matches invert mode
      xorwf		RR1		,W				;set bit off
      movwf		indf						;write it out
      bsf		fsr		,07				;point fsr to port tris
      movf		indf		,W				;get tris data
      iorwf		RR1		,W				;make bit an input
      btfss		status		,C				;bit direction matches bit
      xorwf		RR1		,W				;make bit an output
      movwf		indf						;write it out
      goto		seroutdelay					;wait remainder of bit time
    seroutnorm							;
      movf		indf		,W				;get port data
      iorwf		RR1		,W				;set bit on
      btfss		status		,C				;skip if bit should be on
      xorwf		RR1		,W				;set bit off
      btfsc		R14		,06				;invert if 'N' mode
      xorwf		RR1		,W				;flip for invert
      movwf		indf						;write it out
      bsf		fsr		,07				;point fsr to port tris
      comf		RR1		,W				;get complemented bit mask to W
      andwf		indf		,F				;clear tris bit to set output
      goto		seroutdelay					;wait remainder of bit time
    serialdelay							;
      bsf		RM2		,06				;
    seroutdelay							;
      movf		R14		,W				;get high baud byte
      andlw		0x1F						;mask to our bits
      addlw		0xFF						;fix baud
      movwf		R9						;save it
      movf		R5		,W				;get low baud byte
      addlw		0xF5						;
      btfsc		status		,C				;bump up high byte if low overflowed
      incf		R9		,F				;
      btfss		RM2		,06				;
      goto		pauseUSL					;
      bcf		RM2		,06				;clear short delay mark
      movwf		R0						;save low part
      movlw		0x02						;divide time by 4
      call		shiftR						;
      goto		pauseUSL					;do 1/4 delay
    That's quite a lot of code asking to be placed in the first 2K code space (and kicking your code out).
    The serial always appears to be placed first, then SOUND, then EEPROM, then PAUSE.

    If you use any PAUSE command, this is inserted:
    Code:
    Delay
      clrf		R10						;delay 1
    DelayX								;
      movwf		R1						;delay 2
    DelayXX								;
      movlw		0xFF						;
      addwf		R1		,F				;
      btfss		status		,C				;
      addwf		R10		,F				;
      btfss		status		,C				;
      goto		DoneX						;
      movlw		0x03						;
      movwf		R9						;
      movlw		0xDF						;
      call		pauseUSL					;
      goto		DelayXX						;
      clrf		R9						;
    pauseUSL							;
      addlw		0xE8						;
      movwf		R0						;
      comf		R9		,F				;
      movlw		0xFC						;
      btfss		status		,C				;
      goto		XpauseUSL					;
    pauseX								;
      addwf		R0		,F				;
      btfsc		status		,C				;
      goto		pauseX						;
    XpauseUSL							;
      addwf		R0		,F				;
      clrwdt							;
      incfsz	R9		,F				;
      goto		pauseX						;
      btfsc		R0		,00				;
      goto		pausedoneX					;
    pausedoneX							;
      btfss		R0		,01				;
      goto		pausedone					;
      goto		Done						;
    or on chip-EEPROM Read/Write:

    Code:
    EEPROMread							;read byte from on-chip EEPROM
      bsf		status		,rp0				;for bank 1
      movwf		EEADR						;set the EEPROM address
      bsf		EECON1		,0x0				;EECON1 in bank 3
      movf		EEDATA		,W				;read from data memory
      goto		DoneX						;done
    
    EEPROMwrite							;write byte to on-chip EEPROM
      bsf		status		,rp0				;for EE in bank 1
      movwf		EEDATA						;set the EEPROM data
      bsf		EECON1		,02				;
      movlw		0x55						;unlock the door
      movwf		EECON2						;
      movlw		0xAA						;
      movwf		EECON2						;
      bsf		EECON1		,01				;do the write
    writeloop							;
      btfsc		EECON1		,01				;wait for the write to complete
      goto		writeloop					;
      bcf		EECON1		,02				;lock up when we're done
      goto		DoneX						;
    So bottom line is if you are using any of these, insert them in your code once, straight away
    before bothering with timing, or determining which bank you want your variables to be in.
    Then you can add additional identical commands without worrying about anything else being added.
    All of these commands reuse the code from the first time they were used in a PBP program.
    Cheers, Art.

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    Hi Art,
    I know most of that, the thing I'm having proplem with is this
    You want to keep most called functions (PBP routines) in the first 2K code space to avoid page switching.
    If the calling line (the GOSUB in your "main" routine) ends up in Page 1 while the sub is in Page 0 it STILL needs to switch pages - that's what I'm saying.

    But...Darrel just responded to the post on the MELABS forum with some details and it turns out that GOSUBing from Page 1 to Page 0 does indeed take one instruction less than the other way around - go figure. But (again) if everything fits within the same page (Page 0) then that same GOSUB now takes 3 instructions instead of 2. Go figure...

    /Henrik.

  6. #6
    Join Date
    Aug 2003
    Posts
    985


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    I always thought the PBP author put his routines closest to zero vector
    for the reason I gave. Now, since you sorted me out on that,
    I think it's to avoid bank or page switching in his asm code to both
    make it smaller, and if he didn't always know the internal variables were in bank0,
    timings of the routines would be a pain, just as it can be here.

    If the calling line (the GOSUB in your "main" routine) ends up in Page 1 while the sub is in Page 0 it STILL needs to switch pages - that's what I'm saying.
    There are often only a few loops where timing is an issue, like in the first example of this thread.
    or, for example, something that is sending or receiving bytes at a time in a for next loop can be
    called from anywhere and contained in the first 2K.

    Page 1 to Page 0 does indeed take one instruction less than the other way around - go figure.
    I haven't found the post, but it's cheaper to write a zero value than anything else,
    that is done with a single clrf instruction, but writing a one takes two instructions.

    if everything fits within the same page (Page 0) then that same GOSUB now takes 3 instructions instead of 2. Go figure.
    That one's got me stumped. I would like to see the disassembly.
    A jump from page 0 to page 0 should just be a gosub as if you are using a 2K chip.
    You'll notice in the code above there are no asm gosubs.
    Only returns to the gosubs that called the routines.
    I think they must be more expensive, but that doesn't explain the difference.

  7. #7
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,132


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    Quote Originally Posted by HenrikOlsson View Post
    if everything fits within the same page (Page 0) then that same GOSUB now takes 3 instructions instead of 2. Go figure...
    I think it is because it does not know if it is in page 0 or 1 or else, so a test must be done first?

    Ioannis

  8. #8
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    Hi,
    Here's a link to the thread on MELABS forum. Darrel posted code there which he used to demonstrate, I'm sure you can disassemble that.

    /Henrik.

  9. #9
    Join Date
    Jan 2009
    Location
    Miami, Florida USA
    Posts
    699


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    Quote Originally Posted by HenrikOlsson View Post
    Hi,
    Here's a link to the thread on MELABS forum. Darrel posted code there which he used to demonstrate, I'm sure you can disassemble that.

    /Henrik.
    Hmm, I knew that the used programming space goes down, but I had no idea that it had to do with the GOSUBs. Also, it is good to know that the enhanced chips do not have this issue.
    "No one is completely worthless. They can always serve as a bad example."

    Anonymous

  10. #10
    Join Date
    Oct 2012
    Posts
    82


    Did you find this post helpful? Yes | No

    Default Re: Maximum frequency output from a PIC

    Hi Team,

    I am using the setup from post #43 and I need a clarification on how the duty cycle setting works.
    If I understood the data sheet correctly for a 16 MHz main clock and an output frequency of 250 KHz I have access to 16 steps of duty cycle.
    Also the manual states that you can use CCPR1L which is 8 bit wide and CCP1CON.5 plus CCP1CON.4 so you have access to a 10 bit wide setting.

    My question is who keeps track of individual values and their place in the 10 bit variable.
    Is the user supposed to do the logic or PBP takes care of it?
    For example if I use something like this:

    CCPR1L = 5
    CCP1CON.5 = 1 (an 0 means 0 and an 1 means 2)
    CCP1CON.4= 0 (an 0 means 0 and an 1 means 1)

    Is the result 7 so we just add the two values or is it 21 which comes from 5 shifted twice and add 2 from CCP1CON.5 ?

    Does one have to pick only multiple of 4 when choosing CCPR1L or whatever value is given is taken as a 10 bit value and added to CCP1CON 4 and 5?


    Regards,

    Nick

Similar Threads

  1. internal TMR for frequency output
    By Samoele in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 15th January 2009, 09:38
  2. How to calculate PIC sampling frequency
    By minmin in forum General
    Replies: 1
    Last Post: - 26th September 2006, 18:02
  3. Replies: 2
    Last Post: - 20th January 2006, 21:09
  4. Maximum frequency count on 16F628/4MHz
    By solara in forum mel PIC BASIC Pro
    Replies: 10
    Last Post: - 23rd May 2005, 10:38
  5. Low frequency output
    By barkerben in forum General
    Replies: 5
    Last Post: - 16th November 2004, 15:25

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts