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 because core 1 never will be interrupted by RTOS.
- /*
- * 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);
- }
- }