| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| colin382 
 
 
 Joined: 03 Jun 2020
 Posts: 40
 Location: UK
 
 
			    
 
 | 
			
				| 18F24J11 clock switch not working |  
				|  Posted: Tue May 11, 2021 4:13 am |   |  
				| 
 |  
				| I have a logger application that must run for a long time on a small battery. The data acquired by the logger is written to an SD card once per day. The logger runs on the internal clock at 31000Hz until the SD card is to be written. This action requires a serial port working at 2400 bps or higher, for which a much faster chip clock is needed. I use the 8MHz internal clock.
 I have tried several ways of switching clock rates "on the fly" but none have worked. The attached code is my best effort so far, but although the code runs correctly, the current taken suggests that the chip is always using the high clock rate.
 
 So, dear forum members, is there a way of switching clocks as needed?
  	  | Code: |  	  | /* Investigation of problem with clock change
 Very little latency in the changeover, Microchip DS says 2 old clocks plus
 four new. In this case about 60us, much less than the code timings
 */
 
 // No specific header file, all is in this file
 #include <18F24J11.h>            // from CCS unchanged
 #device ADC=10
 
 #FUSES NOWDT                     //No Watch Dog Timer
 // Default fuses
 #FUSES T1DIG                     //Secondary Oscillator Source may be select regardless of T1CON.3 state
 #FUSES FCMEN                     //Fail-safe clock monitor enabled
 #FUSES IESO                      //Internal External Switch Over mode enabled
 #FUSES DSWDTOSC_INT              //DSWDT uses INTRC as reference clock
 #FUSES RTCOSC_T1                 //RTCC uses Secondary Oscillator as reference source
 #FUSES DSBOR                     //BOR enabled in Deep Sleep
 #FUSES DSWDT                     //Deep Sleep Watchdog Timer enabled
 #FUSES IOL1WAY                   //Allows only one reconfiguration of peripheral pins
 #FUSES MSSPMSK7                  //MSSP uses 7 bit Masking mode
 #FUSES WPFP                      //Write/Erase Protect Page Start/End Location, set to last page or use WPFP=x to set page
 #FUSES WPEND                     //Flash pages WPFP to Configuration Words page are write/erase protected
 #FUSES WPDIS                     //All Flash memory may be erased or written
 
 #use delay(internal=8M)          // needed to define UART
 #use RS232(UART1, stream = Logger)
 setup_uart(baud = 9600, stream = Logger, internal = 8000000);
 #use delay(internal = 31000)     // start with slow clock
 
 // variables
 unsigned char Record[50] = "A long string of no particular interest\r\n";
 // 43 bytes = 430 bits at 9600bps = 44.8 ms
 
 void main() {
 while(TRUE){
 // Using the built-in UART functions
 fprintf(Logger, Record);
 #use delay(internal = 31000)     // back to slow clock
 delay_ms(500);
 // code above works correctly, UART data is good, delay is good.
 // but current 7.3mA, suggesting the clock does not return to 31000Hz.
 // when all references to UART removed, current = 1.4mA.
 }
 }
 | 
 |  |  
		|  |  
		| temtronic 
 
 
 Joined: 01 Jul 2010
 Posts: 9588
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue May 11, 2021 6:41 am |   |  
				| 
 |  
				| re: I have a logger application that must run for a long time on a small battery. The data acquired by the logger is written to an SD card once per day. 
 Have you 'done the math'  to see how big the 'small' battery needs to be  to run for a 'long' time ? Depending on SD card mfr/size it might take a lot of power to store the data. Hmm..how much data ? What 'enviroment' (temperatures) is it located in ? Anything other then 'warm', and battery capacity can be 1/2 or even a 1/3rd of 'rated' aH.
 At least look at Microchip's AN606 as a start to  begin the 'math'.
 When you get the 'number'... double it. 'Little' details like pullups, LEDs,enabled peripherals can steal a few electrons...over time,,,oopsy, battery died....
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue May 11, 2021 7:12 am |   |  
				| 
 |  
				| It will do. 
 You have the FSCM fuse set. If the clock speed drops below about 100KHz,
 it'll switch to the default clock. You need this off.
 
 You need to be setting the oscillator to 8MHz, before you use the UART,
 wait a short while for it to stabilise, do your UART operation, then switch back
 to 31K.
 
 Also your 'setup_uart' line is doing nothing. A code line placed outside of
 the code, has no effect at all.
 |  |  
		|  |  
		| colin382 
 
 
 Joined: 03 Jun 2020
 Posts: 40
 Location: UK
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue May 11, 2021 11:19 am |   |  
				| 
 |  
				| @temtronic Thanks for your interest and observations. The code quoted is of course just the minimum to explain the problem. The project is to run from 3 * AA dry cells and consists of the micro, a SparkFun OpenLog that is only powered when needed (once per day)and one LED using 1mA that is pulsed for 30ms for each logged event- this happens about 2000 times a day on average. The hardware is in a heated residential property. Running from 31000Hz the quiescent current is about 100uA. The 1.4mA quoted originally includes the current taken by a Pickit4.
 
 @Ttelmah
 Thanks for the tip regarding the fail-safe fuse- I rather lazily assumed the CCS Wizard would read my mind and do what was necessary. As an aside, why would it step in when the code is running at a legitimate speed?
 
 The code below implements your suggestions but sad to say the current is still high. I have attached the .lst file in case it helps.
 
  	  | Code: |  	  | /* Investigation of problem with clock change
 This scheme works, note clock speed determined entirely with #use delay
 Very little latency in the changeover, Microchip DS says 2 old clocks plus
 four new. In this case about 60us, much less than the output delay_ms() statements
 */
 
 // No specific header file, all is in this file
 #include <18F24J11.h>            // from CCS unchanged
 #device ADC=10
 
 #FUSES NOWDT                     // No Watch Dog Timer
 #FUSES NOFCMEN                   // no fail-safe (clock) monitor
 
 void main() {
 #use delay(internal=8M)          // needed to define UART
 #use RS232(UART1, baud = 9600, stream = Logger)
 #use delay(internal = 31000)     // start with slow clock
 
 // variables
 unsigned char Record[50] = "A long string of no particular interest\r\n";
 // 43 bytes = 430 bits at 9600bps = 44.8 ms
 
 while(TRUE){
 // Using the built-in UART functions
 #use delay(internal=8M)          // needed for UART operation
 delay_ms(1);                     // wait for things to stabilise
 fprintf(Logger, Record);
 #use delay(internal = 31000)     // back to slow clock
 delay_ms(500);
 // code above works correctly, UART data is good, delay is good.
 // but current 7.3mA, suggesting the clock does not return to 31000Hz.
 // when all references to UART removed, current = 1.4mA.
 // NB 1.3mA of currents above is going to the attached Pickit4
 }
 }
 
 | 
 
 Listing: (In the interest of brevity I have removed most of the comments and Record string
 CCS PCH C Compiler, Version 5.094, xxxxx        11-May-21 18:09
 
 Filename:   Clock change.lst
 
 ROM used:   382 bytes (2%)
 Largest free fragment is 15994
 RAM used:   57 (2%) at main() level
 58 (2%) worst case
 Stack used: 0 locations
 Stack size: 31
 
 0000:  GOTO   0080
 ..................... #include <18F24J11.h>            // from CCS unchanged
 .................... #device PIC18F24J11
 *
 0030:  MOVF   FEF,F
 0032:  BZ    0054
 0034:  MOVFF  FEA,39
 0038:  MOVFF  FE9,38
 003C:  MOVF   FEF,W
 003E:  BTFSS  F9E.4
 0040:  BRA    003E
 0042:  MOVWF  FAE
 0044:  MOVFF  39,FEA
 0048:  MOVFF  38,FE9
 004C:  INCF   FE9,F
 004E:  BTFSC  FD8.2
 0050:  INCF   FEA,F
 0052:  BRA    0030
 0054:  GOTO   016A (RETURN)
 ....................
 .................... #list
 ....................
 .................... #device ADC=10
 ....................
 .................... #FUSES NOWDT                     // No Watch Dog Timer
 .................... #FUSES NOFCMEN                   // no fail-safe (clock) monitor
 ....................
 .................... void main() {
 *
 0080:  CLRF   FF8
 0082:  BCF    FD0.7
 0084:  CLRF   F9B
 0086:  MOVLW  70
 0088:  MOVWF  FD3
 008A:  MOVF   FD3,W
 008C:  BCF    F7E.3
 008E:  MOVLW  0C
 0090:  MOVWF  FB0
 0092:  MOVLW  A2
 0094:  MOVWF  FAD
 0096:  MOVLW  90
 0098:  MOVWF  FAC
 009A:  CLRF   05
 009C:  CLRF   04
 009E:  MOVLW  FF
 00A0:  MOVLB  F
 00A2:  MOVWF  x48
 00A4:  BCF    FC2.6
 00A6:  BCF    FC2.7
 00A8:  MOVF   x49,W
 00AA:  ANDLW  E0
 00AC:  IORLW  1F
 00AE:  MOVWF  x49
 00B0:  MOVLW  07
 00B2:  MOVWF  FB4
 .................... #use delay(internal=8M)          // needed to define UART
 .................... #use RS232(UART1, baud = 9600, stream = Logger)
 .................... #use delay(internal = 31000)     // start with slow clock
 ....................
 .................... // variables
 .................... unsigned char Record[50] = "A long string of no particular interest\r\n";
 00B4:  MOVLW  41
 (and the rest of the bytes)
 0158:  CLRF   2F
 ....................    while(TRUE){
 ....................       // Using the built-in UART functions
 ....................       #use delay(internal=8M)          // needed for UART operation
 *
 0004:  CLRF   FEA
 0006:  MOVLW  38
 0008:  MOVWF  FE9
 000A:  MOVF   FEF,W
 000C:  BTFSC  FD8.2
 000E:  GOTO   002C
 0012:  MOVLW  02
 0014:  MOVWF  01
 0016:  CLRF   00
 0018:  DECFSZ 00,F
 001A:  BRA    0018
 001C:  DECFSZ 01,F
 001E:  BRA    0016
 0020:  MOVLW  97
 0022:  MOVWF  00
 0024:  DECFSZ 00,F
 0026:  BRA    0024
 0028:  DECFSZ FEF,F
 002A:  BRA    0012
 002C:  GOTO   0162 (RETURN)
 ....................       delay_ms(1);                     // wait for things to stabilise
 *
 015A:  MOVLW  01
 015C:  MOVWF  38
 015E:  MOVLB  0
 0160:  BRA    0004
 ....................       fprintf(Logger, Record);
 0162:  CLRF   FEA
 0164:  MOVLW  06
 0166:  MOVWF  FE9
 0168:  BRA    0030
 ....................       #use delay(internal = 31000)     // back to slow clock
 *
 0058:  CLRF   FEA
 005A:  MOVLW  39
 005C:  MOVWF  FE9
 005E:  MOVF   FEF,W
 0060:  BZ    007C
 0062:  MOVLW  02
 0064:  MOVWF  01
 0066:  CLRF   00
 0068:  DECFSZ 00,F
 006A:  BRA    0068
 006C:  DECFSZ 01,F
 006E:  BRA    0066
 0070:  MOVLW  97
 0072:  MOVWF  00
 0074:  DECFSZ 00,F
 0076:  BRA    0074
 0078:  DECFSZ FEF,F
 007A:  BRA    0062
 007C:  GOTO   0174 (RETURN)
 ....................       delay_ms(500);
 *
 016A:  MOVLW  02
 016C:  MOVWF  38
 016E:  MOVLW  FA
 0170:  MOVWF  39
 0172:  BRA    0058
 0174:  DECFSZ 38,F
 0176:  BRA    016E
 0178:  MOVLB  F
 017A:  BRA    015A
 ....................       // code above works correctly, UART data is good, delay is good.
 ....................       }
 .................... }
 017C:  SLEEP
 
 Configuration Fuses:
 Word  1: F4A0   NOWDT STVREN NOXINST NODEBUG NOPROTECT
 Word  2: FF98   INTRC_IO T1DIG NOLPT1OSC NOFCMEN IESO WDT32768
 Word  3: F9FF   DSWDTOSC_INT RTCOSC_T1 DSBOR DSWDT DSWDT_33SEC NOIOL1WAY MSSPMSK5
 Word  4: F1CF   WPFP WPEND NOWPCFG WPDIS
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue May 11, 2021 12:28 pm |   |  
				| 
 |  
				| Look at the ASM code for your #use delay() statements inside main(). It's not switching the oscillator frequency.  That code is the delay code
 for delay_ms().
 
 You need to use the CCS function designed for changing osc freq:
 
 setup_oscillator(OSC_31KHZ);
 
 and
 
 setup_oscillator(OSC_8MHZ);
 
 After each line above,  you can put the appropriate #use delay()
 statement to tell the compiler the current osc frequency.
 
 You should be aware that the #use delay() statement only affects
 code that occurs physically after it in the source file.  The manual says:
 
  	  | Quote: |  	  | Any timing routines (delay_ms(), delay_us(), UART, SPI) that need timing information will use the last defined #USE DELAY.
 | 
 |  |  
		|  |  
		| colin382 
 
 
 Joined: 03 Jun 2020
 Posts: 40
 Location: UK
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue May 11, 2021 4:27 pm |   |  
				| 
 |  
				| @PCM, 
 This is one of the many methods I have tried and failed with. I have now re-visited this solution after Ttelmah suggested turning off the FCMEN fuse, but still no luck.
 
 After RTFM I also modified your suggestion to include OSC_INTRC, e.g. setup_oscillator(OSC_8MHZ | OSC_INTRC); etc. but with no benefit.
 
 To be clear, I added the setup statement immediately before each pre-existing #use delay statement, with the appropriate argements.
 In desperation I also tried only adding the setup statements in main(), and then only in while() but as one might expect, there was no improvement.
 
 It's near midnight here in UK, so closing now and hoping for an overnight epiphany...
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed May 12, 2021 12:05 am |   |  
				| 
 |  
				| The wizard is totally thick. It often generates incorrect values. This is why all the 'old hands' here, 'scream' when people use the wizard....
   
 For your clock switch, you need:
 
  	  | Code: |  	  | #include <18F24J11.h>
 #device ADC=10
 
 #FUSES NOWDT                    //No Watch Dog
 #FUSES NOFCMEN                  //disable FSCM
 
 #use delay(internal=8000000)
 #use RS232(UART1, baud = 9600, stream = Logger, ERRORS)
 //You should _always _ use 'ERRORS' with a hardware UART. Not doing so, unless you
 //add your own error handling code, will result in the UART becoming hung.
 
 // variables
 unsigned char Record[50] = "A long string of no particular interest\r\n";
 // 43 bytes = 430 bits at 9600bps = 44.8 ms
 void main()
 {
 setup_oscillator(OSC_31250 | OSC_INTRC);
 #use delay(CLOCK=31250) //start at slow clock
 
 while(TRUE)
 {
 // Using the built-in UART functions
 setup_oscillator(OSC_8MHZ | OSC_INTRC);
 #use delay(CLOCK=8M)          // needed for UART operation
 delay_ms(1);                     // wait for things to stabilise
 fprintf(Logger, Record);
 setup_oscillator(OSC_31250 | OSC_INTRC);
 #use delay(CLOCK=31250) //back to slow clock
 delay_ms(500);
 // code above works correctly, UART data is good, delay is good.
 // but current 7.3mA, suggesting the clock does not return to 31000Hz.
 // when all references to UART removed, current = 1.4mA.
 // NB 1.3mA of currents above is going to the attached Pickit4
 }
 }
 
 | 
 
 The point is you need both a #use delay, saying what speed the clock
 actually is at (if you want delays to work), and also a separate control
 statement to physically switch the speed. When you put a #use delay
 'inline' in the code, it _does not_ generate the code to change to this
 speed. It only tells the compiler to use this speed in it's calculations
 from this point. The actual clock switching has to be done 'as well'...
 
 So if you code without the setup_oscillator, the listing is:
 
  	  | Code: |  	  | ....................       //setup_oscillator(OSC_8MHZ | OSC_INTRC);
 ....................       #use delay(internal=8M)          // needed for UART operation
 ....................       delay_ms(1);                     // wait for things to stabilise
 
 | 
 
 Note no switching code generated, while as I show, you get:
 
  	  | Code: |  	  | ....................       setup_oscillator(OSC_8MHZ | OSC_INTRC);
 0126:  CLRF   F9B
 0128:  MOVLW  73
 012A:  MOVWF  FD3
 012C:  MOVF   FD3,W
 ....................       #use delay(CLOCK=8M)          // needed for UART operation
 *
 0004:  CLRF   FEA
 0006:  MOVLW  39
 0008:  MOVWF  FE9
 000A:  MOVF   FEF,W
 000C:  BTFSC  FD8.2
 000E:  GOTO   002C
 0012:  MOVLW  02
 0014:  MOVWF  01
 0016:  CLRF   00
 0018:  DECFSZ 00,F
 001A:  BRA    0018
 001C:  DECFSZ 01,F
 001E:  BRA    0016
 0020:  MOVLW  97
 0022:  MOVWF  00
 0024:  DECFSZ 00,F
 0026:  BRA    0024
 0028:  DECFSZ FEF,F
 002A:  BRA    0012
 002C:  GOTO   0136 (RETURN)
 ....................       delay_ms(1);                     // wait for things to stabilise
 
 | 
 
 Showing both the switching code, and the new delay code for this speed.
 |  |  
		|  |  
		| colin382 
 
 
 Joined: 03 Jun 2020
 Posts: 40
 Location: UK
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed May 12, 2021 1:45 pm |   |  
				| 
 |  
				| Thanks Ttelmah, that works exactly as hoped. I did need to add a 2ms delay after the fprintf() to allow the last two bytes to be sent before switching back to the slow clock. My error was putting the initial setup_oscillator() and delay() before main(). 
 There is one remaining issue: the current in the slow clock period is 1.7mA. If I remove all references to the RS232 and the associated setup_oscillator() and delay() so that the chip is always running at 31KHz the current comes down to 0.1mA. Next I left all the clock change stuff in place, but deleted the UART setup and the fprintf() that uses it. The current is then also 0.1mA.
 
 It seems that invoking a UART enables a hardware module that runs continuously. Since there doesn't seem to be a   #unuse RS232()   built-in function, I will resurrect a bitbang UART TXD function I used some time ago. I don't need the RXD side.
 
 Thamks again for your expertise and patience.
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed May 12, 2021 11:21 pm |   |  
				| 
 |  
				| If you look at the setup_UART function, you can use your #use RS232 like this:
 
 #use RS232(UART1, baud = 9600, ERRORS, NOINIT, stream = Logger)
 
 Then when you want to use the UART (immediately after the clock switch),
 use:
 
 setup_UART(TRUE); //will enable the UART
 
 Then once you have finished your printf, use:
 
  	  | Code: |  	  | #BIT TRMT=getenv("BIT:TRMT")
 
 //printf what you want here
 while (TRMT==0)
 ; //this will wait for the UART to finish transmitting
 
 setup_UART(FALSE); //now turns the UART off
 //and now slow your clock speed
 
 | 
 
 This allows you to turn the UART hardware off when you are not using it.
 However the power consumption won't be coming from the UART hardware
 itself, but probably what is connected. Remember the UART TX line will
 be driven high when the UART is idle. It suggests something in the circuit
 is putting a load on this line so when it is driven this way, there is significant
 consumption....
 |  |  
		|  |  
		| colin382 
 
 
 Joined: 03 Jun 2020
 Posts: 40
 Location: UK
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu May 13, 2021 7:08 am |   |  
				| 
 |  
				| Well I would never have thought of that in a million years. It works and the current in slow clock is now 0.1mA. Brilliant.
 Serial data is correct BUT the baud rate is 125K and doesnt change when I  change the #use RS232() baud argument !
 I think this is because the BRG register is left at default (=0), so the baud rate becomes Fosc/64. The list file has no reference to SPBRG1 (at register FB0h)
 I could just write the appropriate value into SPBRG1, but is there a better way?
 
 
 
  	  | Code: |  	  | #include <18F24J11.h>
 #device ADC=10
 
 #FUSES NOWDT                    //No Watch Dog
 #FUSES NOFCMEN                  //disable FSCM
 
 #use delay(internal=8000000)
 #use RS232(UART1, baud = 9600, ERRORS, NOINIT, stream = Logger)
 // Data transfer is correct but at 125Kbaud.
 // #use RS232(UART1, baud = 2400, ERRORS, NOINIT, stream = Logger)
 // attempt to modify baud rate, no effect
 
 // variables
 unsigned char Record[50] = "A long string of no particular interest\r\n";
 // 43 bytes = 430 bits at 9600bps = 44.8 ms
 void main()
 {
 setup_oscillator(OSC_31250 | OSC_INTRC);
 #use delay(CLOCK=31250) //start at slow clock
 
 while(TRUE)
 {
 setup_oscillator(OSC_8MHZ | OSC_INTRC);
 #use delay(CLOCK=8M)          // needed for UART operation
 setup_UART(TRUE);
 delay_ms(1);                  // wait for things to stabilise
 #BIT TRMT=getenv("BIT:TRMT")
 fprintf(Logger, Record);
 while (TRMT==0);              // wait for the UART to finish transmitting
 setup_UART(FALSE);            // now turn the UART off
 setup_oscillator(OSC_31250 | OSC_INTRC);
 #use delay(CLOCK=31250)       // back to slow clock
 delay_ms(5000);               // enough time to measure current
 }
 }
 
 | 
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu May 13, 2021 7:36 am |   |  
				| 
 |  
				| You can include the clock rate in the setup_UART. Normally it shouldn't be needed, but I'd suspect it is getting confused by the clock changes.
 
 setup_UART(9600, Logger, 8000000);
 
 Should put the right BRG value in.
  |  |  
		|  |  
		| colin382 
 
 
 Joined: 03 Jun 2020
 Posts: 40
 Location: UK
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu May 13, 2021 7:59 am |   |  
				| 
 |  
				| That fixed it. Once again, thanks for your help. 
 Until the next time...
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu May 13, 2021 11:40 am |   |  
				| 
 |  
				| Nice to see progress forwards.  |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 
 |  
 Powered by phpBB © 2001, 2005 phpBB Group
 
 |