addi II 1 7 декабря, 2022 Опубликовано 7 декабря, 2022 · Жалоба Подскажите пожалуйста а почему здесь вложенность реализована через программное прерывание? https://github.com/MIPS/FreeRTOS-mips64/blob/master/FreeRTOS/Source/portable/GCC/MIPS64/port.c Получается сначала я захожу в программное и далее из программное в аппаратное Правильно ли я понимаю что программное прерывание сделано чтобы переключать контекст? А разве во FreeRTOS контекст переключается только в этом случае?(как я понимаю в случае вызова yeild самой ОС) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 7 декабря, 2022 Опубликовано 7 декабря, 2022 · Жалоба 5 hours ago, addi II said: Подскажите пожалуйста а почему здесь вложенность реализована через программное прерывание? В port.c нет никаких вложенных прерываний. 5 hours ago, addi II said: А разве во FreeRTOS контекст переключается только в этом случае? Да, особенность архитектуры FreeRTOS. Контекст сохраняется при входе в прерывание, и восстанавливается при выходе. Других мест сохранения/восстановления нет. Поэтому для переключения задач нужно войти в прерывание (иначе контект текущей задачи не сохранить и контект другой не восстановить) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 1 7 декабря, 2022 Опубликовано 7 декабря, 2022 · Жалоба Спасибо, а в каком портровом файле они(сохранение контекста при вложенном прерывании) должны быть?? И что может служить программным прерыванием для переключения контекста -- обычный периферийный таймер??? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 7 декабря, 2022 Опубликовано 7 декабря, 2022 · Жалоба 9 hours ago, addi II said: Спасибо, а в каком портровом файле они(сохранение контекста при вложенном прерывании) должны быть?? В том же самом, что и для не вложенных. Даже больше - это одно и тоде сохранение контекста. Ваш код влоденные прерывания не поддерживает 😞 Манипуляции с контекстом находятся в файле ISR_Support.h - это макросы portSAVE_CONTEXT/portRESTORE_CONTEXT и portYIELD_SAVE/portYIELD_RESTORE (при этом само сохранение находится в макросах _gpctx_load/_gpctx_save в файле ctx.S) Первая пара (portSAVE_CONTEXT/portRESTORE_CONTEXT) используется для прерываний из которых нельзя стелать таск свитч. Эти макросы не перключают стек, и всё было бы хорошо, но они сохраняют и восстанавливают стек поинтер через одну глобальную переменную - uxSavedTaskStackPointer. Соотвественно вложенное прерывание перепишет эту пременную и менее вложенное прерывание снесёт стек к чертям :( Вторая пара макросов при входе в прерывание переключает стеки процессов при входе/выходе. Отдельный стек для ядра вообще не используется - ядро пасётся на стеке текущего процесса. В общем, если убрать uxSavedTaskStackPointer (заменить стеком или вообще убрать - не совсем понятно для чего указатель стека сохраняли, он не должен меняться) то наверное вложенные прерывания будут работать 9 hours ago, addi II said: И что может служить программным прерыванием для переключения контекста -- обычный периферийный таймер??? Нет, там только yield Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 1 8 декабря, 2022 Опубликовано 8 декабря, 2022 · Жалоба 12 hours ago, xvr said: Нет, там только yield Не понял, а как же timer tick interrtupt? Он же как раз выщывает yield Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 8 декабря, 2022 Опубликовано 8 декабря, 2022 · Жалоба 1 hour ago, addi II said: Не понял, а как же timer tick interrtupt? Он же как раз выщывает yield Именно. Yield и вызывает переключение контекстов. Откуда он при этом пришёл все равно. Мог из таймера, мог из нити исполнения. Этот порт поддерживает только вложенность yield прерывания в чего угодно (в том числе и в другие прерывания). Вложенность других прерываний друг в друга не поддерживает (да их там и нет - один таймер, нечему вкладываться) Полная поддержка вложенности прерываний подразумевает возможность произвольной вложенности (на любую глубину) любых прерываний (возможно с некоторыми ограничениями в виде приоритетов). Возможна ограниченная поддержка в виде групп прерываний, при этом группы могут как то вкладываться друг в друга (у вас как раз такая). yield - одна группа, остальные прерывания - вторая. В некоторых других портах FreeRTOS есть полная поддержка вложенных прерываний. Например в ESP32 - там есть отдельный стек для ядра и отслеживание уровня вложенности прерываний. Можете посмотреть, для общего развития 🙂 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 1 17 февраля, 2023 Опубликовано 17 февраля, 2023 · Жалоба Спасибо!, можно еще спросить? У меня почти так как вы описываете, за исключением добавления вложенности Прошу посмотреть на мой порт для MIPS64 аппаратного прерывания для ticlincrement и программного для yield Сейчас работа FreeRTOS не полноценна, первая задача запускается, далее вторая, и все.., нет циклического запуска, хотя задачи с одинаковым приоритетом В отладке вижу что когда наступает восстановление EPC по portRestoreYIELD после первой задачи в EPC вижу адрес второй задачи, но далее при следующем восстановлении по portRestoreYIELD EPC содержит адрес перед последнем exception, тесть адрес во второй задаче(адрес первый задачи который должен где-то храниться после xtaskcreate не перезаписывается в EPC) Вот мой вектор инкрементирования тика: _CP0_TIM_VEC4_handler: // Cause_DC = 1 mfc0 a0, C0_CAUSE li a1, ~(1 << 27) and a0, a0, a1 mtc0 a0, C0_CAUSE ehb di ehb ld sp, xISRStackTop /*Swap to the system stack ????? */ // LA sp, __stack LA gp, _gp /*.macro portSAVE_CONTEXT*/ // Make room for the context. First save the current status so it can be //manipulated, and the cause and EPC registers so their original values are //captured. ADDU sp, sp, -CTX_SIZE REG_S k1, CTX_K1(sp) // k1 is used as the frame pointer. ADDU k1, zero, sp // Save the context into the space just created. /*.macro _gpctx_save*/ /*ld sp, xISRStackTop*/ /* Save general registers. */ /* $27/k1 must be saved prior to using this macro. */ .irp num,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 \ 20,21,22,23,24,25,26,28,29,30,31 REG_S $\num, CTX_REG(\num) (k1) .endr PTR_S $0, CTX_LINK(k1) /* Clear the link field. */ mfhi $9 REG_S $9, CTX_HI0(k1) mflo $10 REG_S $10, CTX_LO0(k1) /* Save CP0 registers. */ PTR_MFC0 $31, C0_EPC ehb /* mfc0 $10, C0_STATUS */ /* ehb */ REG_S $31, CTX_EPC(k1) ehb /* sw $10, CTX_STATUS(k1) */ .endm // Save the stack pointer. LA s6, uxSavedTaskStackPointer REG_S k1, (s6) REG_L k1, CTX_K1(sp) /*.endm*/ jal vPortIncrementTick nop nop /*.macro portRESTORE_CONTEXT*/ LA s6, uxSavedTaskStackPointer REG_L k0, (s6) // Restore the context. /*.macro _gpctx_load*/ REG_L $9, CTX_HI0(k0) REG_L $10, CTX_LO0(k0) mthi $9 mtlo $10 /* Restore the general registers. */ .irp num,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, \ 20,21,22,23,24,25 REG_L $\num, CTX_REG(\num) (k0) .endr /* Restore CP0 registers, kernel registers and stack with interrupts disabled. */ /* di */ /* lw k1, CTX_STATUS(k0) */ /* mtc0 k1, C0_STATUS */ REG_L k1, CTX_EPC(k0) PTR_MTC0 k1, C0_EPC REG_L $27, CTX_REG(27) (k0) REG_L $28, CTX_REG(28) (k0) REG_L $29, CTX_REG(29) (k0) REG_L $30, CTX_REG(30) (k0) REG_L $31, CTX_REG(31) (k0) /* Finally restore k0/$26. */ REG_L $26, CTX_REG(26)(k0) /*.endm*/ LA sp, uxSavedTaskStackPointer REG_L sp, (sp) ADDU sp, sp, CTX_SIZE /*.endm*/ // Count = 0 mtc0 zero, C0_COUNT ehb mfc0 a0, C0_CAUSE li a1, (1 << 27) or a0, a0, a1 mtc0 a0, C0_CAUSE ehb ei ehb eret .end _CP0_TIM_VEC4_handler Вот вектор переключения #mfc0 a0, C0_CAUSE di ehb ld sp, xISRStackTop LA gp, _gp /*portYIELD_SAVE*/ // Make room for the context. First save the current status so it can be //manipulated. daddiu sp, sp, -CTX_SIZE REG_S k1, CTX_K1(sp) // k0cd is used as the frame pointer. move k1, sp // Save the context into the space just created. /*_gpctx_save*/ .irp num,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 \ 20,21,22,23,24,25,27,28,29,30,31 rdpgpr k1, $\num REG_S k1, CTX_REG(\num) (k0) .endr rdpgpr k1, $26 nop nop REG_S k1, CTX_REG(26) (k0) mfhi k1 REG_S k1, CTX_HI0(k0) mflo k1 REG_S k1, CTX_LO0(k0) /* Save CP0 registers. */ PTR_MFC0 k1, C0_EPC REG_S k1, CTX_EPC(k0) // Save the stack pointer to the task. LA s7, pxCurrentTCB REG_L s7, (s7) REG_S k1, (s7) jal vTaskSwitchContext nop nop /*portYIELD_RESTORE*/ // Set the context restore register from the TCB. LA s0, pxCurrentTCB REG_L s0, (s0) REG_L k0, (s0) // The _gpctx_load restore code just wholesale copies the // status register from the context back to the register loosing // any changes that may have occured, 'status' is really global state // You dont enable interrupts on one thread and not another... // So we just copy the current status value into the saved value // so nothing changes on the restore // /***/ mfc0 k1, C0_STATUS sw k1, CTX_STATUS(k0) /***/ /*_gpctx_load*/ REG_L $9, CTX_HI0(k0) REG_L $10, CTX_LO0(k0) mthi $9 mtlo $10 /* Restore the general registers. */ .irp num,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, \ 20,21,22,23,24,25 REG_L $\num, CTX_REG(\num) (k0) .endr /* Restore CP0 registers, kernel registers and stack with interrupts disabled. */ /* di */ /* lw k1, CTX_STATUS(k0) */ /* mtc0 k1, C0_STATUS */ REG_L k1, CTX_EPC(k0) PTR_MTC0 k1, C0_EPC REG_L $27, CTX_REG(27) (k0) REG_L $28, CTX_REG(28) (k0) REG_L $29, CTX_REG(29) (k0) REG_L $30, CTX_REG(30) (k0) REG_L $31, CTX_REG(31) (k0) /* Finally restore k0/$26. */ REG_L $26, CTX_REG(26)(k0) // Restore the stack pointer from the TCB. LA sp, pxCurrentTCB REG_L sp, (sp) REG_L sp, (sp) // Remove stack frame. daddiu sp, sp, CTX_SIZE ei ehb eret .end _SW_VEC1_handler Возможна ли причина отсутствия периодического переключения задач как раз в отсутствии обработки вложенности? Я только не совсем понял что Вы имели ввиду когда говорили что в yield происходит переключение стеков процессов при входе/выходе??? И я не совсем понял нужно ли в обоих векторах делать обработку вложенности или только в yield?? К сожалению не нашел пример на ESP32, взял за основу для PIC32MZ И там в обоих векторах происходит обработка вложенности при этом по коду наскольку я понял если переменная вложенности ноль то идем по топовому указателю стека если не ноль то согласно uxSavedTaskStackPointe, но не понятно что является причиной для инкрекментирования самой переменной Вот хендлер на инкрементировании тика от пика: vPortTickInterruptHandler: /*.macro portSAVE_CONTEXT*/ /* Make room for the context. First save the current status so it can be manipulated, and the cause and EPC registers so their original values are captured. */ mfc0 k0, _CP0_CAUSE addiu sp, sp, -portCONTEXT_SIZE mfc0 k1, _CP0_STATUS /* Also save s7, s6 and s5 so they can be used. Any nesting interrupts should maintain the values of these registers across the ISR. */ sw s7, 48(sp) sw s6, 44(sp) sw s5, 40(sp) sw k1, portSTATUS_STACK_LOCATION(sp) /* Prepare to enable interrupts above the current priority. */ srl k0, k0, 0xa ins k1, k0, 10, 7 srl k0, k0, 0x7 /* This copies the MSB of the IPL, but it would be an error if it was set anyway. */ ins k1, k0, 18, 1 ins k1, zero, 1, 4 /* s5 is used as the frame pointer. */ add s5, zero, sp /* Check the nesting count value. */ la k0, uxInterruptNesting lw s6, (k0) /* If the nesting count is 0 then swap to the the system stack, otherwise the system stack is already being used. */ bne s6, zero, 1f nop /* Swap to the system stack. */ la sp, xISRStackTop lw sp, (sp) /* Increment and save the nesting count. */ 1: addiu s6, s6, 1 sw s6, 0(k0) /* s6 holds the EPC value, this is saved after interrupts are re-enabled. */ mfc0 s6, _CP0_EPC /* Re-enable interrupts. */ mtc0 k1, _CP0_STATUS /* Save the context into the space just created. s6 is saved again here as it now contains the EPC value. No other s registers need be saved. */ sw ra, 120(s5) sw s8, 116(s5) sw t9, 112(s5) sw t8, 108(s5) sw t7, 104(s5) sw t6, 100(s5) sw t5, 96(s5) sw t4, 92(s5) sw t3, 88(s5) sw t2, 84(s5) sw t1, 80(s5) sw t0, 76(s5) sw a3, 72(s5) sw a2, 68(s5) sw a1, 64(s5) sw a0, 60(s5) sw v1, 56(s5) sw v0, 52(s5) sw s6, portEPC_STACK_LOCATION(s5) sw $1, 16(s5) /* Update the task stack pointer value if nesting is zero. */ la s6, uxInterruptNesting lw s6, (s6) addiu s6, s6, -1 bne s6, zero, 1f nop /* Save the stack pointer. */ la s6, uxSavedTaskStackPointer sw s5, (s6) 1: .endm jal vPortIncrementTick nop /*.macro portRESTORE_CONTEXT*/ /* Restore the stack pointer from the TCB. This is only done if the nesting count is 1. */ la s6, uxInterruptNesting lw s6, (s6) addiu s6, s6, -1 bne s6, zero, 1f nop la s6, uxSavedTaskStackPointer lw s5, (s6) 1: /* s6 is loaded as it was used as a scratch register and therefore saved as part of the interrupt context. */ lw s7, 48(s5) lw s6, 44(s5) lw v0, 52(s5) lw v1, 56(s5) lw a0, 60(s5) lw a1, 64(s5) lw a2, 68(s5) lw a3, 72(s5) lw t0, 76(s5) lw t1, 80(s5) lw t2, 84(s5) lw t3, 88(s5) lw t4, 92(s5) lw t5, 96(s5) lw t6, 100(s5) lw t7, 104(s5) lw t8, 108(s5) lw t9, 112(s5) lw s8, 116(s5) lw ra, 120(s5) /* Protect access to the k registers, and others. */ di ehb /* Decrement the nesting count. */ la k0, uxInterruptNesting lw k1, (k0) addiu k1, k1, -1 sw k1, 0(k0) /* Restore the frame when there is no hardware FP support. */ lw k0, portSTATUS_STACK_LOCATION(s5) lw k1, portEPC_STACK_LOCATION(s5) /* Leave the stack in its original state. First load sp from s5, then restore s5 from the stack. */ add sp, zero, s5 lw s5, 40(sp) addiu sp, sp, portCONTEXT_SIZE mtc0 k0, _CP0_STATUS mtc0 k1, _CP0_EPC ehb eret nop .endm /*.end vPortTickInterruptHandler*/ и вот yield: vPortYieldISR: /* Code sequence for no FPU support, the context save requires advance knowledge of the stack frame size when no FPU is being used */ /* Make room for the context. First save the current status so it can be manipulated, and the cause and EPC registers so thier original values are captured. */ addiu sp, sp, -portCONTEXT_SIZE mfc0 k1, _CP0_STATUS /* Also save s6 and s5 so they can be used. Any nesting interrupts should maintain the values of these registers across the ISR. */ sw s6, 44(sp) sw s5, 40(sp) sw k1, portSTATUS_STACK_LOCATION(sp) /* Prepare to re-enabled interrupts above the kernel priority. */ ins k1, zero, 10, 7 /* Clear IPL bits 0:6. */ ins k1, zero, 18, 1 /* Clear IPL bit 7. It would be an error here if this bit were set anyway. */ ori k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) ins k1, zero, 1, 4 /* Clear EXL, ERL and UM. */ /* s5 is used as the frame pointer. */ add s5, zero, sp /* Swap to the system stack. This is not conditional on the nesting count as this interrupt is always the lowest priority and therefore the nesting is always 0. */ la sp, xISRStackTop lw sp, (sp) /* Set the nesting count. */ la k0, uxInterruptNesting addiu s6, zero, 1 sw s6, 0(k0) /* s6 holds the EPC value, this is saved with the rest of the context after interrupts are enabled. */ mfc0 s6, _CP0_EPC /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ mtc0 k1, _CP0_STATUS /* Save the context into the space just created. s6 is saved again here as it now contains the EPC value. */ sw ra, 120(s5) sw s8, 116(s5) sw t9, 112(s5) sw t8, 108(s5) sw t7, 104(s5) sw t6, 100(s5) sw t5, 96(s5) sw t4, 92(s5) sw t3, 88(s5) sw t2, 84(s5) sw t1, 80(s5) sw t0, 76(s5) sw a3, 72(s5) sw a2, 68(s5) sw a1, 64(s5) sw a0, 60(s5) sw v1, 56(s5) sw v0, 52(s5) sw s7, 48(s5) sw s6, portEPC_STACK_LOCATION(s5) /* s5 and s6 has already been saved. */ sw s4, 36(s5) sw s3, 32(s5) sw s2, 28(s5) sw s1, 24(s5) sw s0, 20(s5) sw $1, 16(s5) /* s7 is used as a scratch register as this should always be saved across nesting interrupts. */ /* Save the stack pointer to the task. */ la s7, pxCurrentTCB lw s7, (s7) sw s5, (s7) /* Set the interrupt mask to the max priority that can use the API. The yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever raise the IPL value and never lower it. */ di ehb mfc0 s7, _CP0_STATUS ins s7, zero, 10, 7 ins s7, zero, 18, 1 ori s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1 /* This mtc0 re-enables interrupts, but only above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ mtc0 s6, _CP0_STATUS ehb /* Clear the software interrupt in the core. */ mfc0 s6, _CP0_CAUSE ins s6, zero, 8, 1 mtc0 s6, _CP0_CAUSE ehb /* Clear the interrupt in the interrupt controller. */ la s6, IFS0CLR addiu s4, zero, 2 sw s4, (s6) jal vTaskSwitchContext nop /* Clear the interrupt mask again. The saved status value is still in s7. */ mtc0 s7, _CP0_STATUS ehb /* Restore the stack pointer from the TCB. */ la s0, pxCurrentTCB lw s0, (s0) lw s5, (s0) lw $1, 16(s5) lw s0, 20(s5) lw s1, 24(s5) lw s2, 28(s5) lw s3, 32(s5) lw s4, 36(s5) /* s5 is loaded later. */ lw s6, 44(s5) lw s7, 48(s5) lw v0, 52(s5) lw v1, 56(s5) lw a0, 60(s5) lw a1, 64(s5) lw a2, 68(s5) lw a3, 72(s5) lw t0, 76(s5) lw t1, 80(s5) lw t2, 84(s5) lw t3, 88(s5) lw t4, 92(s5) lw t5, 96(s5) lw t6, 100(s5) lw t7, 104(s5) lw t8, 108(s5) lw t9, 112(s5) lw s8, 116(s5) lw ra, 120(s5) /* Protect access to the k registers, and others. */ di ehb /* Set nesting back to zero. As the lowest priority interrupt this interrupt cannot have nested. */ la k0, uxInterruptNesting sw zero, 0(k0) /* Switch back to use the real stack pointer. */ add sp, zero, s5 /* Restore the real s5 value. */ lw s5, 40(sp) /* Pop the status and epc values. */ lw k1, portSTATUS_STACK_LOCATION(sp) lw k0, portEPC_STACK_LOCATION(sp) /* Remove stack frame. */ addiu sp, sp, portCONTEXT_SIZE /* Restore the status and EPC registers and return */ mtc0 k1, _CP0_STATUS mtc0 k0, _CP0_EPC ehb eret nop .end vPortYieldISR Прошу помочь, а то я немного запутался И самое худшее в этом я не могу понять где храниться адреса задач для переключения контекста Согласно документации после xtaskCreate создаются два блока памяти - данных задачи, и стека задачи Но не понятно куда привязать тогда pxCurrentTCB и "Task Frame"?? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 18 февраля, 2023 Опубликовано 18 февраля, 2023 · Жалоба 18 hours ago, addi II said: Я только не совсем понял что Вы имели ввиду когда говорили что в yield происходит переключение стеков процессов при входе/выходе??? Именно то, чего у вас нет 🙂 При переключении контекста вы должны сохранить контекст текущей задачи в стек задачи, НЕ В ISR! Потом текущий указатель стека (пользовательской задачи) сохранить в поле в текущем TCB (на него указывает глобальная переменная pxCurrentTCB). И только потом переключаться на стек ISR. Восстановление аналогично - загрузка пользовательского стека из TCB, восстановление контекста и возврат. Переключение задач обеспечивается изменением этого самого pxCurrentTCB на другой TCB. 18 hours ago, addi II said: Но не понятно куда привязать тогда pxCurrentTCB и "Task Frame"?? pxCurrentTCB включает пользовательский SP первым полем (если у вас нет поддержки SMP). А Task Frame - это и есть пользовательский стек. Создаётся при создании задачи и указатель на него (на верх или низ - зависит от архитектуры) кладётся в TCB, куда потом будет указывать pxCurrentTCB. Оттуда и стартует пользовательская задача (стековый фрейм для её запуска формируется при создании задачи). В дальнейшем он будет живым стеком задачи, и SP задачи (пока FreeRTOS обрабатывает прерывание) будет храниться в TCB Для обработки вложенных прерываний нужно перед тем, как сохранять состояние понять откуда вас позвали - из пользовательского кода или из ISR. Если из пользовательского кода, то делаете всё как описанно выше. Если из ISR, то никаких стеков вообще переключать не нужно - сохраняете контекст прямо по текущему SP 18 hours ago, addi II said: но не понятно что является причиной для инкрекментирования самой переменной Вход в ISR. При первом входе (от пользователя) она будет 0, при дальнейших вложенных ISR - больше нуля. При выходе из ISR - декрементируется Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 1 19 февраля, 2023 Опубликовано 19 февраля, 2023 · Жалоба спасибо большое за ответ! немного запутался в определениях Как я понял Task Frame - это и есть пользовательский стек(сам буфер находящийся по пользовательскому SP) А стек задачи = контекст текущей задачи = текущий указатель стека =>pxCurrentTCB = пользовательский SP А есть ли сама структура Task Frame (хотелось бы знать где именно находиться адрес задач для переключения)? И я не совсем понял что подразумевается под стеком ISR Как я понял мне нужно в tickinterrupthandler добавить стек ISR или/и стек задачи А в yield также? И Вы не могли бы дать ссылку на пример отражающий вышесказанное Спасибо!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 20 февраля, 2023 Опубликовано 20 февраля, 2023 · Жалоба On 2/19/2023 at 1:58 AM, addi II said: А есть ли сама структура Task Frame У каждого порта она своя, т.к. хранит регистры процессора, которые очевидно разные. И опять же, от порта зависит - есть для него явно описанная структура или нет. On 2/19/2023 at 1:58 AM, addi II said: И я не совсем понял что подразумевается под стеком ISR То, на что указывает xISRStackTop On 2/19/2023 at 1:58 AM, addi II said: Как я понял мне нужно в tickinterrupthandler добавить стек ISR или/и стек задачи Они у вас там есть. Но переключение между ними неправильное. У FreeRTOS есть 2 вида стеков - стек задачи (он же пользовательский). Этот вид существует по 1 штуке на каждую задачу. Когда задача испольняется он активен (загружен в sp) И стек прерываний - он всего один на всех, на нём запускаются прерывания самой FreeRTOS. Соотвественно в обработчике прерываний вы должны сначала сохранить все регистры по текущему sp, а потом выяснить, на каком имеено стеке вы сейчас находитесь (анализом уровня вложенности прерываний в спеу. переменной). Если на пользовательском - то сохранить sp в текущий TCB и переключить sp на xISRStackTop. Если нет, то ничего делать не надо. При выходе обратный процесс - переключение стека (если надо), восстановление регистров, возврат из прерывания On 2/19/2023 at 1:58 AM, addi II said: А в yield также? yield ничем не отличается от обычного прерывания. On 2/19/2023 at 1:58 AM, addi II said: И Вы не могли бы дать ссылку на пример отражающий вышесказанное ESP32 порт это делает - https://github.com/FreeRTOS/FreeRTOS-Kernel/tree/bb6071e1df3168a64dc2ce79de8aa91b7995ba23/portable/ThirdParty/GCC/Xtensa_ESP32 PS. Он ещё и SMP - некоторые вещи могут быть не совсем такие, как в обычном FreeRTOS Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 1 20 февраля, 2023 Опубликовано 20 февраля, 2023 · Жалоба Спасибо, получается от пика то же переключение не правильное(я приводил выше пример также)? Я старался брать основу пример от пика. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 20 февраля, 2023 Опубликовано 20 февраля, 2023 · Жалоба 1 hour ago, addi II said: Спасибо, получается от пика то же переключение не правильное(я приводил выше пример также)? Yield полностью соотвествует тому, что я написал. Таймерное прерывание не соотвествует - оно не обновляет TCB, а вместо этого сохраняет пользовательский стек в глобальной переменной uxSavedTaskStackPointer Это значит, что либо из него невозможно переключение задач (для этого нужно переключить TCB), либо код переключений в port.c берёт на себя манипуляцию по перекладыванию данных между TCB и uxSavedTaskStackPointer В принципе это (невозможность переключения задач из прерываний) тоже вполне возможный вариант, но тогда порт должен обеспечить вызов yield прерывания (откуда и происходит переключения задач) сразу после окончания обработки всей цепочки вложенных прерываний. Для этого скорее всего потребуется аппаратная поддержка. Я не знаком со всеми вариантами архитектур FreeRTOS, увы. Я разбирался с ESP32 и RISC-V. Про остальные могу только догадываться 😞 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 1 20 февраля, 2023 Опубликовано 20 февраля, 2023 · Жалоба Понял спасибо, а принцип обновления TCB в таймерном прерывании должен быть таким же как для Yeild(у пика)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
addi II 1 20 февраля, 2023 Опубликовано 20 февраля, 2023 (изменено) · Жалоба и еще вопрос, - по поводу SP и GP(global pointer) и их инициализацию Нужно ли инициализировать Task Frame?, какую инициализацию должна делать vPortStartFirstTask ? И как динамически передавать в ISR GP?(в примерах от пика этого нет, но gp FreeRTOS использует как минимум в инкременте тика) Изменено 20 февраля, 2023 пользователем addi II Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 20 февраля, 2023 Опубликовано 20 февраля, 2023 · Жалоба 8 hours ago, addi II said: Понял спасибо, а принцип обновления TCB в таймерном прерывании должен быть таким же как для Yeild(у пика)? Желательно. Иначе вам придётся устраивать танцы с бубном если захочется переключить задачи по таймеру (а оно обязательно захочестя) 5 hours ago, addi II said: Нужно ли инициализировать Task Frame?, какую инициализацию должна делать vPortStartFirstTask ? Она создаёт специальный фрейм, который при выходе из него (в момент выхода из прерывания) запустит main таска 5 hours ago, addi II said: И как динамически передавать в ISR GP?(в примерах от пика этого нет, но gp FreeRTOS использует как минимум в инкременте тика) Загружать явно в нужное значение (и не забыть его созранить и восстеновить в контексте) Либо проинициализировать один раз в стартапе и больше НИГДЕ не трогать (вполне нормальный подход, если весь код ваш, и вы нигде руками gp не меняете) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться