Merge branch 'bugfix/ets_delay_on_app_cpu' into 'master'

esp32: ets_update_cpu_frequency should set tick scale for both CPUs

ets_update_cpu_frequency ROM function updates g_ticks_per_us, which is has two copies, one for each CPU.
The APP CPU copy of g_ticks_per_us never got updated, resulting in shorter delays produced by ets_delay_us on the APP CPU.

This MR replaces ROM ets_update_cpu_frequency with a copy in IRAM which updates scaling factors on both of the CPUs.

So now we get expected delays (in microseconds):
```
ets_delay_us core=0 expected=50000 actual=50014
ets_delay_us core=1 expected=50000 actual=50015
vTaskDelay core=0 expected=50000 actual=49428
vTaskDelay core=1 expected=50000 actual=50000
```

Reported on the forum: http://esp32.com/viewtopic.php?f=2&t=713#p3722

See merge request !373
This commit is contained in:
Ivan Grokhotkov
2017-01-07 18:45:14 +08:00
3 changed files with 69 additions and 1 deletions

View File

@@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include <stdint.h> #include <stdint.h>
#include "esp_attr.h"
#include "rom/ets_sys.h" #include "rom/ets_sys.h"
#include "rom/uart.h" #include "rom/uart.h"
#include "sdkconfig.h" #include "sdkconfig.h"
@@ -66,3 +67,10 @@ void esp_set_cpu_freq(void)
ets_update_cpu_frequency(freq_mhz); ets_update_cpu_frequency(freq_mhz);
} }
void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
{
extern uint32_t g_ticks_per_us_pro; // g_ticks_us defined in ROM for PRO CPU
extern uint32_t g_ticks_per_us_app; // same defined for APP CPU
g_ticks_per_us_pro = ticks_per_us;
g_ticks_per_us_app = ticks_per_us;
}

View File

@@ -202,7 +202,7 @@ PROVIDE ( ets_timer_init = 0x400084e8 );
PROVIDE ( ets_timer_setfn = 0x40008350 ); PROVIDE ( ets_timer_setfn = 0x40008350 );
PROVIDE ( ets_unpack_flash_code = 0x40007018 ); PROVIDE ( ets_unpack_flash_code = 0x40007018 );
PROVIDE ( ets_unpack_flash_code_legacy = 0x4000694c ); PROVIDE ( ets_unpack_flash_code_legacy = 0x4000694c );
PROVIDE ( ets_update_cpu_frequency = 0x40008550 ); /* PROVIDE ( ets_update_cpu_frequency = 0x40008550 ); */ /* Updates g_ticks_per_us on the current CPU only; not on the other core */
PROVIDE ( ets_waiti0 = 0x400067d8 ); PROVIDE ( ets_waiti0 = 0x400067d8 );
PROVIDE ( exc_cause_table = 0x3ff991d0 ); PROVIDE ( exc_cause_table = 0x3ff991d0 );
PROVIDE ( _exit_r = 0x4000bd28 ); PROVIDE ( _exit_r = 0x4000bd28 );
@@ -1725,6 +1725,8 @@ PROVIDE ( xthal_memcpy = 0x4000c0bc );
PROVIDE ( xthal_set_ccompare = 0x4000c058 ); PROVIDE ( xthal_set_ccompare = 0x4000c058 );
PROVIDE ( xthal_set_intclear = 0x4000c1ec ); PROVIDE ( xthal_set_intclear = 0x4000c1ec );
PROVIDE ( _xtos_set_intlevel = 0x4000bfdc ); PROVIDE ( _xtos_set_intlevel = 0x4000bfdc );
PROVIDE ( g_ticks_per_us_pro = 0x3ffe01e0 );
PROVIDE ( g_ticks_per_us_app = 0x3ffe40f0 );
/* /*
These functions are xtos-related (or call xtos-related functions) and do not play well These functions are xtos-related (or call xtos-related functions) and do not play well
with multicore FreeRTOS. Where needed, we provide alternatives that are multicore with multicore FreeRTOS. Where needed, we provide alternatives that are multicore

View File

@@ -0,0 +1,58 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "unity.h"
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
typedef struct {
int delay_us;
int method;
} delay_test_arg_t;
static void test_delay_task(void* p)
{
const delay_test_arg_t* arg = (delay_test_arg_t*) p;
struct timeval tv_start, tv_stop;
gettimeofday(&tv_start, NULL);
switch (arg->method) {
case 0:
ets_delay_us(arg->delay_us);
break;
case 1:
vTaskDelay(arg->delay_us / portTICK_PERIOD_MS / 1000);
break;
default:
TEST_FAIL();
}
gettimeofday(&tv_stop, NULL);
int real_delay_us = (tv_stop.tv_sec - tv_start.tv_sec) * 1000000 +
tv_stop.tv_usec - tv_start.tv_usec;
printf("%s core=%d expected=%d actual=%d\n", arg->method ? "vTaskDelay" : "ets_delay_us",
xPortGetCoreID(), arg->delay_us, real_delay_us);
TEST_ASSERT_TRUE(abs(real_delay_us - arg->delay_us) < 1000);
vTaskDelay(1);
vTaskDelete(NULL);
}
TEST_CASE("ets_delay produces correct delay on both CPUs", "[delay]")
{
int delay_ms = 50;
const delay_test_arg_t args = { .delay_us = delay_ms * 1000, .method = 0 };
xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void*) &args, 3, NULL, 0);
vTaskDelay(delay_ms / portTICK_PERIOD_MS + 1);
xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void*) &args, 3, NULL, 1);
vTaskDelay(delay_ms / portTICK_PERIOD_MS + 1);
}
TEST_CASE("vTaskDelay produces correct delay on both CPUs", "[delay]")
{
int delay_ms = 50;
const delay_test_arg_t args = { .delay_us = delay_ms * 1000, .method = 1 };
xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void*) &args, 3, NULL, 0);
vTaskDelay(delay_ms / portTICK_PERIOD_MS + 1);
xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void*) &args, 3, NULL, 1);
vTaskDelay(delay_ms / portTICK_PERIOD_MS + 1);
}