|
| 1 | +/* |
| 2 | + * Copyright 2024 SZIGETI János |
| 3 | + * |
| 4 | + * This file is part of Bilis ESP32 Basic, which is released under GNU General Public License.version 3. |
| 5 | + * See LICENSE or <https://www.gnu.org/licenses/> for full license details. |
| 6 | + */ |
| 7 | +#include <stdbool.h> |
| 8 | +#include <stdlib.h> |
| 9 | +#include <inttypes.h> |
| 10 | + |
| 11 | +#include "esp_attr.h" |
| 12 | +#include "main.h" |
| 13 | +#include "defines.h" |
| 14 | +#include "dport.h" |
| 15 | +#include "romfunctions.h" |
| 16 | +#include "timg.h" |
| 17 | +#include "uart.h" |
| 18 | +#include "utils/uartutils.h" |
| 19 | + |
| 20 | +// =================== Hard constants ================= |
| 21 | +// #1: Timings |
| 22 | +#define UART_FREQ_HZ 115200U |
| 23 | +#define CYCLE_PERIOD_MS 1000U |
| 24 | + |
| 25 | +// #2: Sizes |
| 26 | +#define TEST_PATTERN_LENGTH 1000U |
| 27 | +#define MSG_INC_STEP 100U |
| 28 | + |
| 29 | +// #3: Channels |
| 30 | +#define UHCI_INT_CH 23U |
| 31 | + |
| 32 | +// ============= Local types =============== |
| 33 | +typedef struct { |
| 34 | + uint32_t u12Size : 12; |
| 35 | + uint32_t u12Length : 12; |
| 36 | + uint32_t rsvd24: 6; |
| 37 | + uint32_t bEof : 1; |
| 38 | + uint32_t bOwner : 1; |
| 39 | + void *pcData; |
| 40 | + void *psNext; |
| 41 | +} UdmaDescriptor; |
| 42 | + |
| 43 | +// ================ Local function declarations ================= |
| 44 | +static void _pattern_init(); |
| 45 | +static void _uart_init(); |
| 46 | +static void _uart_cycle(uint64_t u64tckNow); |
| 47 | +static void _uhci_isr(void *pvParam); |
| 48 | + |
| 49 | +// =================== Global constants ================ |
| 50 | +const bool gbStartAppCpu = START_APP_CPU; |
| 51 | +const uint16_t gu16Tim00Divisor = TIM0_0_DIVISOR; |
| 52 | +const uint64_t gu64tckSchedulePeriod = (CLK_FREQ_HZ / SCHEDULE_FREQ_HZ); |
| 53 | + |
| 54 | +// =================== Local constants ================ |
| 55 | +static const TimerId gsTimer = {.eTimg = TIMG_0, .eTimer = TIMER0}; |
| 56 | +static const EUartController geUart = UART_CTL0; |
| 57 | +static const EUdmaController geUdma = UDMA_CTL0; |
| 58 | +static const ECpu eIntCpu = CPU_PRO; |
| 59 | + |
| 60 | +static UART_Type *gpsUART = geUart == UART_CTL0? &gsUART0 : geUart == UART_CTL1 ? &gsUART1 : &gsUART2; |
| 61 | +static UHCI_Type *gpsUHCI = geUdma == UDMA_CTL0? &gsUHCI0 : &gsUHCI1; |
| 62 | + |
| 63 | +// ==================== Local Data ================ |
| 64 | +static uint8_t gu8Phase = 0; |
| 65 | + |
| 66 | +static uint64_t gu64TckUartTxStart; |
| 67 | +static uint64_t gu64TckUartTxStop; |
| 68 | + |
| 69 | +static uint64_t gu64TckUdmaTxStart; |
| 70 | +static uint64_t gu64TckUdmaTxStop; |
| 71 | +static volatile uint64_t gu64TckUdmaTxDone; |
| 72 | +static volatile uint64_t gu64TckUdmaTxTotalEof; |
| 73 | + |
| 74 | +static char gacTestPattern[TEST_PATTERN_LENGTH]; |
| 75 | +static UdmaDescriptor gsUdmaDesc; |
| 76 | + |
| 77 | +// Implementation |
| 78 | + |
| 79 | +// ==================== Local Functions ================ |
| 80 | +static void _pattern_init() { |
| 81 | + for (int i = 0; i < TEST_PATTERN_LENGTH; ++i) { |
| 82 | + gacTestPattern[i] = '0' + (i % 10); |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +static void _uart_init() { |
| 87 | +#define UART_CLKDIV_INT HZ2APBTICKS(UART_FREQ_HZ) |
| 88 | +#define UART_CLKDIV_REM (APB_FREQ_HZ - (UART_CLKDIV_INT * UART_FREQ_HZ)) |
| 89 | +#define UART_CLKDIV_FRAG ((16U * UART_CLKDIV_REM) / UART_FREQ_HZ) |
| 90 | + // version A) |
| 91 | + gpsUART->CLKDIV.u20ClkDiv = UART_CLKDIV_INT; |
| 92 | + gpsUART->CLKDIV.u4ClkDivFrag = UART_CLKDIV_FRAG; |
| 93 | + // version B) |
| 94 | + // gpsUART->CLKDIV.raw = UART_CLKDIV_INT | (UART_CLKDIV_FRAG << 20); // this line results in shorter binary file |
| 95 | +#undef UART_CLKDIV_FRAG |
| 96 | +#undef UART_CLKDIV_REM |
| 97 | +#undef UART_CLKDIV_INT |
| 98 | + uart_init_udma(geUart, geUdma); |
| 99 | + gpsUHCI->INT_ENA = (1 << UHCI_INT_OUTTOTALEOF) | (1 << UHCI_INT_OUTDONE); |
| 100 | + |
| 101 | + // register ISR and enable it |
| 102 | + RegAddr prDportIntMap = (eIntCpu == CPU_PRO ? &dport_regs()->PRO_UHCI0_INTR_MAP : &dport_regs()->APP_UHCI0_INTR_MAP); |
| 103 | + prDportIntMap += geUdma; |
| 104 | + |
| 105 | + *prDportIntMap = UHCI_INT_CH; |
| 106 | + _xtos_set_interrupt_handler_arg(UHCI_INT_CH, _uhci_isr, 0); |
| 107 | + ets_isr_unmask(1 << UHCI_INT_CH); |
| 108 | + |
| 109 | +} |
| 110 | + |
| 111 | +static void _uart_cycle(uint64_t u64tckNow) { |
| 112 | + static uint64_t u64tckNext = 0; |
| 113 | + static uint32_t u32MsgLen = MSG_INC_STEP; |
| 114 | + |
| 115 | + if (u64tckNext <= u64tckNow) { |
| 116 | + switch (gu8Phase) { |
| 117 | + case 0: |
| 118 | + uart_printf(gpsUART, "Sending message of %u bytes\r\n", u32MsgLen); |
| 119 | + break; |
| 120 | + case 1: |
| 121 | + gu64TckUartTxStart = timg_ticks(gsTimer); |
| 122 | + for (int i = 0; i < u32MsgLen; ++i) { |
| 123 | + gpsUART->FIFO = gacTestPattern[i]; |
| 124 | + } |
| 125 | + gu64TckUartTxStop = timg_ticks(gsTimer); |
| 126 | + break; |
| 127 | + case 2: |
| 128 | + uart_printf(gpsUART, "\r\nUART TX duration: %u ns\r\n", (uint32_t)((gu64TckUartTxStop - gu64TckUartTxStart) / TICKS_PER_US)); |
| 129 | + break; |
| 130 | + case 3: |
| 131 | + gsUdmaDesc = (UdmaDescriptor) { |
| 132 | + .bEof = true, |
| 133 | + .bOwner = true, |
| 134 | + .pcData = gacTestPattern, |
| 135 | + .psNext = NULL, |
| 136 | + .u12Length = u32MsgLen, |
| 137 | + .u12Size = TEST_PATTERN_LENGTH |
| 138 | + }; |
| 139 | + gpsUHCI->INT_CLR = -1; |
| 140 | + gu64TckUdmaTxStart = timg_ticks(gsTimer); |
| 141 | + gpsUHCI->OUT_LINK = (((uint32_t)&gsUdmaDesc)&0xfffff) | (1 << 29); |
| 142 | + gu64TckUdmaTxStop = timg_ticks(gsTimer); |
| 143 | + break; |
| 144 | + case 4: |
| 145 | + uart_printf(gpsUART, "\r\nUDMA TX duration: %u (send), %u (done), %u (eof) ns)\r\n", |
| 146 | + (uint32_t)((gu64TckUdmaTxStop - gu64TckUdmaTxStart) / TICKS_PER_US), |
| 147 | + (uint32_t)((gu64TckUdmaTxDone - gu64TckUdmaTxStart) / TICKS_PER_US), |
| 148 | + (uint32_t)((gu64TckUdmaTxTotalEof - gu64TckUdmaTxStart) / TICKS_PER_US)); |
| 149 | + break; |
| 150 | + } |
| 151 | + ++gu8Phase; |
| 152 | + if (gu8Phase == 5) { |
| 153 | + gu8Phase = 0; |
| 154 | + u32MsgLen+=MSG_INC_STEP; |
| 155 | + if (TEST_PATTERN_LENGTH < u32MsgLen) { |
| 156 | + u32MsgLen = MSG_INC_STEP; |
| 157 | + } |
| 158 | + } |
| 159 | + u64tckNext += MS2TICKS(CYCLE_PERIOD_MS); |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +IRAM_ATTR static void _uhci_isr(void *pvParam) { |
| 164 | + bool bOutDoneEvent = gpsUHCI->INT_ST & (1 << UHCI_INT_OUTDONE); |
| 165 | + bool bOutTotalEofEvent = gpsUHCI->INT_ST & (1 << UHCI_INT_OUTTOTALEOF); |
| 166 | + if (bOutDoneEvent) { |
| 167 | + gu64TckUdmaTxDone = timg_ticks(gsTimer); |
| 168 | + gpsUHCI->INT_CLR = 1 << UHCI_INT_OUTDONE; |
| 169 | + } |
| 170 | + if (bOutTotalEofEvent) { |
| 171 | + gu64TckUdmaTxTotalEof = timg_ticks(gsTimer); |
| 172 | + gpsUHCI->INT_CLR = 1 << UHCI_INT_OUTTOTALEOF; |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +// ====================== Interface functions ========================= |
| 177 | + |
| 178 | +void prog_init_pro_pre() { |
| 179 | + _uart_init(); |
| 180 | + _pattern_init(); |
| 181 | +} |
| 182 | + |
| 183 | +void prog_init_app() { |
| 184 | +} |
| 185 | + |
| 186 | +void prog_init_pro_post() { |
| 187 | +} |
| 188 | + |
| 189 | +void prog_cycle_app(uint64_t u64tckNow) { |
| 190 | +} |
| 191 | + |
| 192 | +void prog_cycle_pro(uint64_t u64tckNow) { |
| 193 | + _uart_cycle(u64tckNow); |
| 194 | +} |
0 commit comments