To get 4 MHz you set bit 6-3 of OSCCON to 1101 (page 71 of the data sheet).
I suggested that in a comment, and it apparently solved the problem.
The internal oscillator should be running when the device is reset, so you merely have to change those bits and you should be running from it at 4 MHz, instead of the 4 MHz crystal.
What you are trying to do is tricky, but very educational (if you are prepared to spend a lot of effort).
First, you must realise that this kind of PC-only (as opposed to PC+SP) task switching (which is the only thing you can do on a plain 12 or 14-bit PIC core) will only work when all the yield() statements in a task are in the same funtion: they can't be in a called function, and the compiler must not have messed with the function structure (as optimization might do).
Next:
currentTask->pch = PCLATH;\
currentTask->pcl = PCL + 8;\
asm("goto _taskswitcher");
- You seem to assume that PCLATH is the upper bits of the program counter, as PCL is the lower bits. This is NOT the case. When you write to PCL the PCLATH bits are written to the PC, but the upper PC bits are never (implicitly) written to PCLATH. Re-read the relevant section of the datasheet.
- Even if PCLATH was the upper bits of the PC, this would get you into trouble when the instruction after the goto is on not on the same 256-instruction 'page' as the first instruction.
- the plain goto will not work when _taskswitcher is not in the current PCLATH page, you will need an LGOTO or equivalent.
A solution to your PCLATH problem is to declare a label after the goto, and write the lower and upper bits of that label to your pch and pcl locations. But I am not sure you can declare a 'local' label in inline assembly. You sure can in plain MPASM (Olin will smile).
Lastly, to this kind of context switching you must save and restore ALL context that the compiler might depend on, which might include
- indirection register(s)
- status flags
- scratch memory locations
- local variables that might overlap in memory because the compiler does not realise that your tasks must be independent
- other things I can't imagine right now but the compiler author might use in the next version of the compiler (they tend to be very imaginative)
The PIC architecture is more problematic in this respect because a lot of resources are loacted all over the memory map, where more traditional architectures have them in registers or on the stack. As a consequence, PIC compilers often do not generate reentrant code, which is what you definitely need to do the things you want (again, Olin will probaly smile and assemble along.)
If you are into this for the joy of writng an task switcher I suggest that you swicth to a CPU that has a more traditional organization, like an ARM or Cortex. If you are stuck with your feet in a concrete plate of PICs, study existing PIC switchers (for instance salvo/pumkin?).
Best Answer
Summary:
You need to set
OSCF
(bit 3) to0
in thePCON
register in your code (i.e. during runtime) when you want the PIC INTOSC (Internal Oscillator) to run at a nominal 48 kHz (actually anywhere between 31.4 kHz and 78.62 kHz) instead of the power-on INTOSC default frequency of 4 MHz.Details:
The problem is that none of the things you list actually set the INTOSC hardware to 48 kHz. Based on what you said, it seems your software assumes the CPU will run at 48 kHz, but your hardware will still run at the default 4 MHz INTOSC frequency.
Yes, that's what I expect.
85 faster x 48 kHz = 4 MHz (approx.)
This result suggests that your MCU was actually still running at the default INTOSC frequency of 4 MHz.
The important point is that you cannot configure that PIC to run at 48 kHz from power-on. If you set the CONFIG BITS (a.k.a. Fuses) to one of the two variants of INTOSC setting, then the MCU will use the internal 4 MHz frequency at power-on.
Then, when you want to switch it to 48 kHz (perhaps at the start of your
main()
but perhaps elsewhere in your code - it's up to you to choose) you then setOSCF
(bit 3) to0
in thePCON
register - that bit is what switches the INTOSC frequency from 4 MHz to 48 kHz (after a short switchover transition).See section 14.2.8 "SPECIAL FEATURE: DUAL-SPEED OSCILLATOR MODES" on page 101 of the PIC16F628A datasheet for more details.
Also note that the datasheet does not specify the accuracy of the 48 kHz clock (only the 4 MHz clock accuracy is specified there). However the PIC16F628A errata shows that the 48 kHz clock can actually vary between 31.4 kHz to 78.62 kHz.