mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
Add the ability to set clock frequencies on STM32F4 chips (like Pico) with E.setClock (fix #52)
This commit is contained in:
parent
37b447f960
commit
a2fb33f01a
@ -8,6 +8,7 @@
|
||||
Add .removeListener (fix #30)
|
||||
Added better micro:bit `show()` that works well with Graphics
|
||||
Add `require("Flash").getFree()` as multiplatform way to find free flash pages (fix #815)
|
||||
Add the ability to set clock frequencies on STM32F4 chips (like Pico) with E.setClock (fix #52)
|
||||
|
||||
1v85 : Ensure HttpServerResponse.writeHead actually sends the header right away
|
||||
- enables WebSocket Server support from JS
|
||||
|
||||
@ -68,6 +68,7 @@ def htmlify(d):
|
||||
d = re.sub(r'`([^`]+)`', r'<code>\1</code>', d) # code tags
|
||||
d = re.sub(r'\[([^\]]*)\]\(([^\)]*)\)', r'<a href="\2">\1</a>', d) # links tags
|
||||
d = re.sub(r'([^">])(http://[^ ]+)', r'\1<a href="\2">\2</a>', d) # links tags
|
||||
d = re.sub(r'\n###([^\n]*)', r'<B>\1</B>', d) # Heading
|
||||
|
||||
lines = d.split("\n");
|
||||
lines.append("");
|
||||
@ -77,7 +78,7 @@ def htmlify(d):
|
||||
if line[0:2]=="* " and starStart==False:
|
||||
starStart=idx
|
||||
if line[0:2]!="* ":
|
||||
if starStart!=False and starStart+2<idx:
|
||||
if starStart!=False and starStart+2<=idx:
|
||||
l = lines[starStart:idx]
|
||||
for i in range(0,len(l)):
|
||||
l[i] = "<li>"+l[i][1:]+"</li>"
|
||||
|
||||
@ -401,10 +401,11 @@ JsVarFloat jshReadVRef();
|
||||
* default to `rand()` */
|
||||
unsigned int jshGetRandomNumber();
|
||||
|
||||
/** Change the processor speed - the number is given in Hz.
|
||||
* This returns the *actual* clock speed set - so if unimplemented
|
||||
* just return what we actually have. */
|
||||
unsigned int jshSetSystemClockFreq(unsigned int freq);
|
||||
/** Change the processor clock info. What's in options is platform
|
||||
* specific - you should update the docs for jswrap_espruino_setClock
|
||||
* to match what gets implemented here. The return value is the clock
|
||||
* speed in Hz though. */
|
||||
unsigned int jshSetSystemClock(JsVar *options);
|
||||
|
||||
/** Hacky definition of wait cycles used for WAIT_UNTIL.
|
||||
* TODO: make this depend on known system clock speed? */
|
||||
|
||||
@ -733,26 +733,51 @@ JsVar *jswrap_espruino_memoryArea(int addr, int len) {
|
||||
|
||||
/*JSON{
|
||||
"type" : "staticmethod",
|
||||
"ifndef" : "SAVE_ON_FLASH",
|
||||
"class" : "E",
|
||||
"name" : "setFreq",
|
||||
"generate" : "jswrap_espruino_setFreq",
|
||||
"name" : "setClock",
|
||||
"generate" : "jswrap_espruino_setClock",
|
||||
"params" : [
|
||||
["freq","int","The frequency in hz to set Espruino to run at"]
|
||||
["options","JsVar","Platform-specific options for setting clock speed"]
|
||||
],
|
||||
"return" : ["int","The actual frequency set to"]
|
||||
"return" : ["int","The actual frequency the clock has been set to"]
|
||||
}
|
||||
This sets the clock frequency of Espruino. It is only available on some boards.
|
||||
This sets the clock frequency of Espruino's processor. It will return `0` if
|
||||
it is unimplemented or the clock speed cannot be changed.
|
||||
|
||||
**Note:**
|
||||
**Note:** On pretty much all boards, UART, SPI, I2C, PWM, etc will change
|
||||
frequency and will need setting up again in order to work.
|
||||
|
||||
### STM32F4
|
||||
|
||||
Options is of the form `{ M: int, N: int, P: int, Q: int }` - see the 'Clocks'
|
||||
section of the microcontroller's reference manual for what these mean.
|
||||
|
||||
* System clock = 8Mhz * N / ( M * P )
|
||||
* USB clock (should be 48Mhz) = 8Mhz * N / ( M * Q )
|
||||
|
||||
Optional arguments are:
|
||||
|
||||
* `latency` - flash latency from 0..15
|
||||
* `PCLK1` - Peripheral clock 1 divisor (default: 2)
|
||||
* `PCLK2` - Peripheral clock 2 divisor (default: 4)
|
||||
|
||||
The Pico's default is `{M:8, N:336, P:4, Q:7, PCLK1:2, PCLK2:4}`, use
|
||||
`{M:8, N:336, P:8, Q:7, PCLK:1, PCLK2:2}` to halve the system clock speed
|
||||
while keeping the peripherals running at the same speed (omitting PCLK1/2
|
||||
will lead to the peripherals changing speed too).
|
||||
|
||||
On STM32F4 boards (eg. Espruino Pico), the USB clock needs to be kept at 48Mhz
|
||||
or USB will fail to work. You'll also experience USB instability if the processor
|
||||
clock falls much below 48Mhz.
|
||||
|
||||
### ESP8266
|
||||
|
||||
Just specify an integer value, either 80 or 160 (for 80 or 160Mhz)
|
||||
|
||||
* On STM32F1 boards (eg Espruino Original, USB will stop working if you
|
||||
change the clock speed).
|
||||
* On pretty much all boards, UART, PWM, etc will change
|
||||
speed and will need setting up again in order to work.
|
||||
* STM32 will attempt to match
|
||||
*/
|
||||
int jswrap_espruino_setFreq(int freq) {
|
||||
return jshSetSystemClockFreq(freq);
|
||||
int jswrap_espruino_setClock(JsVar *options) {
|
||||
return jshSetSystemClock(options);
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
|
||||
@ -31,7 +31,7 @@ JsVar *jswrap_espruino_toArrayBuffer(JsVar *str);
|
||||
JsVar *jswrap_espruino_toUint8Array(JsVar *args);
|
||||
JsVar *jswrap_espruino_toString(JsVar *args);
|
||||
JsVar *jswrap_espruino_memoryArea(int addr, int len);
|
||||
int jswrap_espruino_setFreq(int freq);
|
||||
int jswrap_espruino_setClock(JsVar *options);
|
||||
|
||||
int jswrap_espruino_reverseByte(int v);
|
||||
void jswrap_espruino_dumpTimers();
|
||||
|
||||
@ -1024,3 +1024,7 @@ unsigned int jshGetRandomNumber() {
|
||||
/* EFM32 TODO This is not random */
|
||||
return 1337;
|
||||
}
|
||||
|
||||
unsigned int jshSetSystemClock(JsVar *options) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1258,6 +1258,16 @@ void jshFlashErasePage(
|
||||
res == SPI_FLASH_RESULT_ERR ? "error" : "timeout");
|
||||
}
|
||||
|
||||
unsigned int jshSetSystemClock(JsVar *options) {
|
||||
int newFreq = jsvGetInteger(options);
|
||||
if (newFreq != 80 && newFreq != 160) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid frequency value, must be 80 or 160.");
|
||||
return 0;
|
||||
}
|
||||
system_update_cpu_freq(newFreq);
|
||||
return system_get_cpu_freq()*1000000;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for end of runtime. This should never be called and has been
|
||||
|
||||
@ -189,6 +189,8 @@ void jswrap_ESP8266_dumpSocketInfo(void) {
|
||||
["freq", "JsVar", "Desired frequency - either 80 or 160."]
|
||||
]
|
||||
}
|
||||
**Note:** This is deprecated. Use `E.setClock(80/160)`
|
||||
**Note:**
|
||||
Set the operating frequency of the ESP8266 processor. The default is 160Mhz.
|
||||
|
||||
**Warning**: changing the cpu frequency affects the timing of some I/O operations, notably of software SPI and I2C, so things may be a bit slower at 80Mhz.
|
||||
@ -197,16 +199,7 @@ Set the operating frequency of the ESP8266 processor. The default is 160Mhz.
|
||||
void jswrap_ESP8266_setCPUFreq(
|
||||
JsVar *jsFreq //!< Operating frequency of the processor. Either 80 or 160.
|
||||
) {
|
||||
if (!jsvIsInt(jsFreq)) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid frequency.");
|
||||
return;
|
||||
}
|
||||
int newFreq = jsvGetInteger(jsFreq);
|
||||
if (newFreq != 80 && newFreq != 160) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid frequency value, must be 80 or 160.");
|
||||
return;
|
||||
}
|
||||
system_update_cpu_freq(newFreq);
|
||||
jshSetSystemClock(jsFreq);
|
||||
}
|
||||
|
||||
//===== ESP8266.getState
|
||||
@ -262,7 +255,7 @@ JsVar *jswrap_ESP8266_getState() {
|
||||
"generate" : "jswrap_ESP8266_getFreeFlash",
|
||||
"return" : ["JsVar", "Array of objects with `addr` and `length` properties describing the free flash areas available"]
|
||||
}
|
||||
**Note:** This is deprecated. Use `require("flash").getFreee()`
|
||||
**Note:** This is deprecated. Use `require("flash").getFree()`
|
||||
*/
|
||||
JsVar *jswrap_ESP8266_getFreeFlash() {
|
||||
return jshFlashGetFree();
|
||||
@ -435,3 +428,5 @@ void jswrap_ESP8266_neopixelWrite(Pin pin, JsVar *jsArrayOfData) {
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -804,3 +804,7 @@ JsVar *jshFlashGetFree() {
|
||||
void jshFlashErasePage(uint32_t addr) { }
|
||||
void jshFlashRead(void *buf, uint32_t addr, uint32_t len) { memset(buf, 0, len); }
|
||||
void jshFlashWrite(void *buf, uint32_t addr, uint32_t len) { }
|
||||
|
||||
unsigned int jshSetSystemClock(JsVar *options) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -271,5 +271,9 @@ void jshFlashRead(void *buf, uint32_t addr, uint32_t len) {
|
||||
void jshFlashWrite(void *buf, uint32_t addr, uint32_t len) {
|
||||
}
|
||||
|
||||
unsigned int jshSetSystemClock(JsVar *options) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
} // extern C
|
||||
|
||||
@ -740,3 +740,7 @@ JsVarFloat jshReadVRef() {
|
||||
unsigned int jshGetRandomNumber() {
|
||||
return (unsigned int) nrf_utils_get_random_number();
|
||||
}
|
||||
|
||||
unsigned int jshSetSystemClock(JsVar *options) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2855,61 +2855,79 @@ void jshFlashWrite(void *buf, uint32_t addr, uint32_t len) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Change the processor speed - the number is given in Hz.
|
||||
* This returns the *actual* clock speed set - so if unimplemented
|
||||
* just return what we actually have. */
|
||||
unsigned int jshSetSystemClockFreq(unsigned int freq) {
|
||||
// see system_stm32f4xx.c
|
||||
unsigned int m = 8; // divisor (usually crystal in Mhz) <= 63
|
||||
unsigned int n = 336; // (freq+4000000) / (m*1000000); // 192-432
|
||||
unsigned int p = 2; // CPU divisor 2,4,6,8
|
||||
unsigned int q = 7; // USB divisor (must be 48Mhz) 4-15
|
||||
int diff = -1;
|
||||
unsigned int im,in,ip;
|
||||
// Exhaustively search for best clock combo
|
||||
for (im=1;im<=63;im++) {
|
||||
unsigned int mfreq = 8000000 / im;
|
||||
for (in=192;in<=432;in++) {
|
||||
unsigned int nfreq = mfreq * in;
|
||||
unsigned int iq = nfreq / 48000000;
|
||||
if (iq<4) iq=4;
|
||||
if (iq>15) iq=15;
|
||||
unsigned int qfreq = nfreq / iq;
|
||||
int jshSetSystemClockPClk(JsVar *options, const char *clkName) {
|
||||
JsVar *v = jsvObjectGetChild(options, clkName, 0);
|
||||
JsVarInt i = jsvGetIntegerAndUnLock(v);
|
||||
if (i==1) return RCC_HCLK_Div1;
|
||||
if (i==2) return RCC_HCLK_Div2;
|
||||
if (i==4) return RCC_HCLK_Div4;
|
||||
if (i==8) return RCC_HCLK_Div8;
|
||||
if (i==16) return RCC_HCLK_Div16;
|
||||
if (v) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid %s value %d", clkName, i);
|
||||
return -2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ip=2;ip<=8;ip+=2) {
|
||||
unsigned int pfreq = nfreq / ip;
|
||||
int d = (int)pfreq - (int)freq;
|
||||
if (d<0) d=-d;
|
||||
if (qfreq!=48000000) d += 1000000000; // discourage choosing bad USB clocks!
|
||||
if (diff<0 || d<=diff) {
|
||||
m = im;
|
||||
n = in;
|
||||
p = ip;
|
||||
q = iq;
|
||||
diff = d;
|
||||
}
|
||||
}
|
||||
unsigned int jshSetSystemClock(JsVar *options) {
|
||||
// see system_stm32f4xx.c for clock configurations
|
||||
#ifdef STM32F4
|
||||
unsigned int m = (unsigned int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "M", 0));
|
||||
unsigned int n = (unsigned int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "N", 0));
|
||||
unsigned int p = (unsigned int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "P", 0));
|
||||
unsigned int q = (unsigned int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "Q", 0));
|
||||
if (!IS_RCC_PLLM_VALUE(m)) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid PLL M value %d", m);
|
||||
return 0;
|
||||
}
|
||||
if (!IS_RCC_PLLN_VALUE(n)) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid PLL N value %d", n);
|
||||
return 0;
|
||||
}
|
||||
if (!IS_RCC_PLLP_VALUE(p)) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid PLL P value %d", p);
|
||||
return 0;
|
||||
}
|
||||
if (!IS_RCC_PLLQ_VALUE(q)) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid PLL Q value %d", q);
|
||||
return 0;
|
||||
}
|
||||
uint8_t latency = 255;
|
||||
JsVar *v = jsvObjectGetChild(options, "latency", 0);
|
||||
if (v) {
|
||||
latency = (uint8_t)jsvGetIntegerAndUnLock(v);
|
||||
if (!IS_FLASH_LATENCY(latency)) {
|
||||
jsExceptionHere(JSET_ERROR, "Invalid flash latency %d", latency);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
int pclk1 = jshSetSystemClockPClk(options, "PCLK1");
|
||||
if (pclk1<-1) return 0;
|
||||
int pclk2 = jshSetSystemClockPClk(options, "PCLK2");
|
||||
if (pclk2<-1) return 0;
|
||||
|
||||
jsiConsolePrintf("CLK M=%d N=%d P=%d Q=%d\n",m,n,p,q);
|
||||
jshTransmitFlush();
|
||||
int i;for (i=0;i<100;i++) jshDelayMicroseconds(1000);
|
||||
|
||||
|
||||
if (freq>84000000) FLASH_SetLatency(FLASH_Latency_6);
|
||||
else FLASH_SetLatency(FLASH_Latency_2);
|
||||
|
||||
// Run off external clock - 8Mhz - while we configure everything
|
||||
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
|
||||
// set latency
|
||||
if (latency!=255) FLASH_SetLatency(latency);
|
||||
if (pclk1>=0) RCC_PCLK1Config(pclk1);
|
||||
if (pclk2>=0) RCC_PCLK2Config(pclk2);
|
||||
// update PLL
|
||||
RCC_PLLCmd(DISABLE);
|
||||
RCC_PLLConfig(RCC_PLLSource_HSE, m, n, p, q);
|
||||
RCC_PLLCmd(ENABLE);
|
||||
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {}
|
||||
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
|
||||
SystemCoreClockUpdate();
|
||||
// force recalculate of the timer speeds
|
||||
SystemCoreClockUpdate();
|
||||
#ifdef USE_RTC
|
||||
jshResetRTCTimer();
|
||||
hasSystemSlept = true;
|
||||
#endif
|
||||
return SystemCoreClock;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user