Using this mechanism it is possible to get cycles of 300ns. But there is a drawback:
The task in core 0 MUST run without a taskswitch, delay etc. That is possible, but it must have the lowest priority.
And that means, it will run in a perfect uninterrupted loop - until a forced taskswitch after one ms will interrupt this loop.
Maybe more often depending on the other tasks running. And the delay than my be some ms !
There are different solutions. One is to use the semaphore (s.o.). That needs 2 µs latency to start the waiting task RTOS_2 in core 0.. After that you get a cylcetime of ~300ns (disable interrupts for core 0).
Here is the source to show superfast interaction:
External interrupt detected by task Core1 --300ns--> RTOS_2 (core 0) reacts.
Use it with a scope or a logic analyser: 2700000 served interrupts/s
(Pins 18 and 19 must be shortened)
BTW: a cooperative multitasking using only core 1 may be an other solution
Code: Untitled.c Select all
/*
* FastIRQGlobalVar
*
* Copyright (c) 2019, Dipl. Phys. Helmut Weber.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Helmut Weber ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the CoopOS library.
*
* Author: Helmut Weber <Dph.HelmutWeber@web.de>
*
* $Id: Task.h,v 1.1 2019/04/02 helmut Exp $
*/
//#pragma GCC optimize ("O2")
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/portmacro.h"
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "esp_task_wdt.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "rom/uart.h"
#include "driver/touch_pad.h"
#include "driver/gpio.h"
#include "soc/gpio_periph.h"
#include "freertos/semphr.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
// Dimensions the buffer that the task being created will use as its stack.
// NOTE: This is the number of bytes the stack will hold, not the number of
// words as found in vanilla FreeRTOS.
#define STACK_SIZE 4096
// Structure that will hold the TCB of the task being created.
StaticTask_t xTaskBuffer;
// Buffer that the task being created will use as its stack. Note this is
// an array of StackType_t variables. The size of StackType_t is dependent on
// the RTOS port.
StackType_t xStack[ STACK_SIZE ];
#define PinA GPIO_NUM_18 // output shortcut > _____
#define PinB GPIO_NUM_19 // input < _____|----- scope
TaskHandle_t xHandle1 = NULL;
TaskHandle_t xHandle2 = NULL;
volatile int LinkCore1Core0=0;
#define LONG_TIME 0xffff
/*
* Macro to check the outputs of TWDT functions and trigger an abort if an
* incorrect code is returned.
*/
#define CHECK_ERROR_CODE(returned, expected) ({ \
if(returned != expected){ \
printf("TWDT ERROR\n"); \
abort(); \
} \
})
inline uint32_t IRAM_ATTR micros()
{
uint32_t ccount;
asm volatile ( "rsr %0, ccount" : "=a" (ccount) );
return ccount;
}
void IRAM_ATTR delayMicroseconds(uint32_t us)
{
if(us){
uint32_t m = micros();
while( (micros() - m ) < us ){
asm(" nop");
}
}
}
void Core1( void* p) {
gpio_set_direction(PinA, GPIO_MODE_OUTPUT);
gpio_set_direction(PinB, GPIO_MODE_INPUT );
printf("Start Core 1\n");
vTaskDelay(1000);
// I do not want an RTOS-Tick here
portDISABLE_INTERRUPTS(); // YEAH
while(1) {
register int level;
level=REG_READ(GPIO_IN_REG) & (1<< PinB );
if (level) {
REG_WRITE(0x3ff4400c, 1<<PinA);// Low at 160 ns
LinkCore1Core0=1;
}
}
}
// Function that creates a task to be pinned at Core 1
void StartCore1( void )
{
TaskHandle_t xHandle = NULL;
xHandle = xTaskCreateStaticPinnedToCore(
Core1, // Function that implements the task.
"Core1", // Text name for the task.
STACK_SIZE, // Stack size in bytes, not words.
( void * ) 1, // Parameter passed into the task.
tskIDLE_PRIORITY+2,
xStack, // Array to use as the task's stack.
&xTaskBuffer, // Variable to hold the task's data structure.
1); // Core 1
}
void RTOS_1(void *p) {
while(1) {
esp_task_wdt_reset();
printf("RTOS-1\n"); // demo for full function
vTaskDelay(1000);
}
}
void RTOS_2(void *p) {
while(1) {
REG_WRITE(0x3ff44008, 1<<PinA);// High
while (LinkCore1Core0==0);
REG_WRITE(0x3ff44008, 1<<PinA);// High
// ... do something
}
}
void app_main(void)
{
gpio_set_direction(PinA, GPIO_MODE_OUTPUT);
gpio_set_direction(PinB, GPIO_MODE_INPUT );
xTaskCreate(
RTOS_1, // Function that implements the task.
"RTOS-1", // Text name for the task.
STACK_SIZE, // Stack size in bytes, not words.
( void * ) 1, // Parameter passed into the task.
tskIDLE_PRIORITY+2,
&xHandle1); // Variable to hold the task's data structure.
// Watchdog satisfied by RTOS_1:
CHECK_ERROR_CODE(esp_task_wdt_init(2 /*sec*/, false), ESP_OK);
CHECK_ERROR_CODE(esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(0)), ESP_OK);
CHECK_ERROR_CODE(esp_task_wdt_add(xHandle1), ESP_OK);
xTaskCreate(
RTOS_2, // Function that implements the task.
"RTOS-2", // Text name for the task.
STACK_SIZE, // Stack size in bytes, not words.
( void * ) 1, // Parameter passed into the task.
tskIDLE_PRIORITY+1,
&xHandle2); // Variable to hold the task's data structure.
StartCore1();
while(1) {
vTaskDelay(10000);
}
}