diff --git a/arch/Kconfig b/arch/Kconfig index 5a51595281a8e..66d5c231d096a 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -182,8 +182,6 @@ config DSPIC select STACK_SENTINAL select ATOMIC_OPERATIONS_C select ARCH_HAS_VECTOR_TABLE_RELOCATION - select CPU_HAS_ICACHE - select CACHE_MANAGEMENT select TICKLESS_CAPABLE help dspic architecture diff --git a/arch/dspic/CMakeLists.txt b/arch/dspic/CMakeLists.txt index fc07eabc00031..f8fdb8e045490 100644 --- a/arch/dspic/CMakeLists.txt +++ b/arch/dspic/CMakeLists.txt @@ -3,6 +3,6 @@ if(CONFIG_BIG_ENDIAN) else() set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-little) endif() -zephyr_include_directories(${XCDSC_TOOLCHAIN_PATH}/support/generic/h/) +zephyr_include_directories(${DFP_ROOT}/support/generic/h/) zephyr_include_directories(include) add_subdirectory(core) diff --git a/arch/dspic/Kconfig b/arch/dspic/Kconfig index 45ebe011c0ff7..17eb1492e2924 100644 --- a/arch/dspic/Kconfig +++ b/arch/dspic/Kconfig @@ -20,4 +20,11 @@ config NUM_IRQS config GEN_IRQ_START_VECTOR default 0 +config DSPIC33_IRQ_OFFLOAD_IRQ + int "IRQ number for irq_offload()" + default 34 + help + Select the interrupt number used by irq_offload(). + This must be a valid, software-triggerable interrupt on the dsPIC33. + endmenu diff --git a/arch/dspic/core/CMakeLists.txt b/arch/dspic/core/CMakeLists.txt index ecc7a0ea64868..2e9dba116d1ee 100644 --- a/arch/dspic/core/CMakeLists.txt +++ b/arch/dspic/core/CMakeLists.txt @@ -4,7 +4,7 @@ zephyr_library_sources( cpu_idle.c fatal.c irq_manage.c - isr_wrapper.c + isr_wrapper.S prep_c.c thread.c swap.c @@ -13,6 +13,7 @@ zephyr_library_sources( init.S vector_table.S reset1.S + irq_offload.c ) zephyr_linker_sources(ROM_START SORT_KEY 0x00 vector_table.ld) diff --git a/arch/dspic/core/fatal.c b/arch/dspic/core/fatal.c index c9b9e75185af6..f6fd1bf240f44 100644 --- a/arch/dspic/core/fatal.c +++ b/arch/dspic/core/fatal.c @@ -16,7 +16,7 @@ LOG_MODULE_REGISTER(dspic, 4); volatile uint32_t reason, address; -#define EXCEPTION_HANDLER __attribute__((interrupt, no_auto_psv, weak)) +#define EXCEPTION_HANDLER __attribute__((interrupt, no_auto_psv, weak, naked)) #define BUS_ERROR_MASK 0xF #define MATH_ERROR_MASK 0x1F #define GENERAL_TRAP_MASK 0x8000000Fu diff --git a/arch/dspic/core/irq_manage.c b/arch/dspic/core/irq_manage.c index 51f9eb1328060..4f9f1e9d146a9 100644 --- a/arch/dspic/core/irq_manage.c +++ b/arch/dspic/core/irq_manage.c @@ -18,7 +18,6 @@ void z_irq_spurious(const void *unused) ARG_UNUSED(unused); while (1) { } - return; } void arch_irq_enable(unsigned int irq) @@ -31,8 +30,6 @@ void arch_irq_enable(unsigned int irq) /* Enable the interrupt by setting it's bit in interrupt enable register*/ *int_enable_reg[reg_index] |= (uint32_t)(1u << bit_pos); - - return; } int arch_irq_is_enabled(unsigned int irq) @@ -56,8 +53,34 @@ void arch_irq_disable(unsigned int irq) /* Disable the interrupt by clearing it's bit in interrupt enable register*/ *int_enable_reg[reg_index] &= (uint32_t)(~(1u << bit_pos)); +} + +bool arch_dspic_irq_isset(unsigned int irq) +{ + volatile uint32_t *int_ifs_reg[] = {&IFS0, &IFS1, &IFS2, &IFS3, &IFS4, + &IFS5, &IFS6, &IFS7, &IFS8}; + volatile int ret_ifs = false; + unsigned int reg_index = irq / (sizeof(uint32_t) << 3); + unsigned int bit_pos = irq % (sizeof(uint32_t) << 3); - return; + if ((bool)(void *)(*int_ifs_reg[reg_index] & (uint32_t)(1U << bit_pos))) { + ret_ifs = true; + } + return ret_ifs; +} + + + +void z_dspic_enter_irq(int irq) +{ + volatile uint32_t *int_ifs_reg[] = {&IFS0, &IFS1, &IFS2, &IFS3, &IFS4, + &IFS5, &IFS6, &IFS7, &IFS8}; + + unsigned int reg_index = (unsigned int)irq / (sizeof(uint32_t) << 3); + unsigned int bit_pos = (unsigned int)irq % (sizeof(uint32_t) << 3); + + /* Enable the interrupt by setting it's bit in interrupt enable register*/ + *int_ifs_reg[reg_index] |= (uint32_t)(1u << bit_pos); } #ifdef __cplusplus diff --git a/arch/dspic/core/irq_offload.c b/arch/dspic/core/irq_offload.c new file mode 100644 index 0000000000000..b20c7eb21c9cb --- /dev/null +++ b/arch/dspic/core/irq_offload.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025, Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +static irq_offload_routine_t _offload_routine; +static const void *offload_param; + +void z_irq_do_offload(void) +{ + irq_offload_routine_t tmp; + + if (_offload_routine != NULL) { + + tmp = _offload_routine; + _offload_routine = NULL; + + tmp((const void *)offload_param); + } +} + +void handler(void) +{ + z_irq_do_offload(); +} + +void arch_irq_offload_init(void) +{ + IRQ_CONNECT(CONFIG_DSPIC33_IRQ_OFFLOAD_IRQ, 1, handler, NULL, 0); +} + +void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) +{ + uint32_t key = irq_lock(); + + _offload_routine = routine; + offload_param = parameter; + irq_enable(CONFIG_DSPIC33_IRQ_OFFLOAD_IRQ); + z_dspic_enter_irq(CONFIG_DSPIC33_IRQ_OFFLOAD_IRQ); + irq_unlock(key); +} diff --git a/arch/dspic/core/isr_wrapper.S b/arch/dspic/core/isr_wrapper.S new file mode 100644 index 0000000000000..e5da315d487d0 --- /dev/null +++ b/arch/dspic/core/isr_wrapper.S @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2025, Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + + + +.LC0: + .long _IFS0 + .long _IFS1 + .long _IFS2 + .long _IFS3 + .long _IFS4 + .long _IFS5 + .long _IFS6 + .long _IFS7 + .long _IFS8 + + .section .text,code + .section .isr.text._COMMONInterrupt,keep,code,keep + .align 4 + .global __COMMONInterrupt ; export + .type __COMMONInterrupt,@function +__COMMONInterrupt: + .section .isr.text._COMMONInterrupt,keep,code,keep + lnk #0x4 + mov.l w8, [w15++] + mov.sl #__kernel,w8 + add.l [w8],#1,[w8] + mov.w _INTTREGbits,w0 + and.l #(0x1ff&0xFFFF),w0 + sub.l w0,#9,w0 + mov.sl #__sw_isr_table,w1 + sl.l w0,#3,w0 + add.l w0,w1,w2 + mov.l [w2+4],w1 + mov.l [w2],w0 + + + call w1 + call _arch_dspic_irq_clear + + + sub.l [w8],#1,w0 + mov.l w0,[w8] + cp.l w0,#0 + bra nz,.L2 + mov.sl #__kernel+20,w1 + mov.l [w1],w1 + mov.sl #__kernel+8,w0 + mov.l [w0],w0 + cp.l w1,w0 + bra z,.L2 + cp0.b _z_sys_post_kernel + bra z,.L2 + mov.bz _INTCON1bits+1,w0 + bfext.l #7,#1,w0,w0 + mov.l w0,[w14] + bclr.b _INTCON1+1,#7 + mov.l [w14],w0 + mov.l [--w15], w8 + ulnk + CTXTSWP #0x0 + mov.l w0, [w15++] + mov.l sr, w0 + and #0xe0, w0 + bra nz, 1f + mov.l [--w15], w0 + ulnk + mov.l w2, [w15++] + mov.l w1, [w15++] + mov.l w0, [w15++] + mov.l #_swap_working_set, w0 + mov.l [--w15], [w0++] + mov.l [--w15], [w0++] + mov.l [--w15], [w0] + mov.l [--w15], w1 + mov.l sr, [w15++] + mov.l w1, [w15++] + mov.l [w0--], w2 + mov.l [w0--], w1 + mov.l [w0], w0 + mov.l w0, [w15++] + 1: + mov.l [--w15], w0 + push RCOUNT + push.l fsr + push.l fcr + mov.l w0, [w15++] + mov.l w1, [w15++] + mov.l w2, [w15++] + mov.l w3, [w15++] + mov.l w4, [w15++] + mov.l w5, [w15++] + mov.l w6, [w15++] + mov.l w7, [w15++] + push.l f0 + push.l f1 + push.l f2 + push.l f3 + push.l f4 + push.l f5 + push.l f6 + push.l f7 + lnk #0x4 + + mov.l #__kernel, w0 + mov.l #0x8, w1 + add w0, w1, w1 + mov.l [w1], w2 + mov.l #0x28, w1 + add w2, w1, w1 + + mov.l w8, [w1++] + mov.l w9, [w1++] + mov.l w10, [w1++] + mov.l w11, [w1++] + mov.l w12, [w1++] + mov.l w13, [w1++] + mov.l w14, [w1++] + mov.l f8, [w1++] + mov.l f9, [w1++] + mov.l f10, [w1++] + mov.l f11, [w1++] + mov.l f12, [w1++] + mov.l f13, [w1++] + mov.l f14, [w1++] + mov.l f15, [w1++] + mov.l f16, [w1++] + mov.l f17, [w1++] + mov.l f18, [w1++] + mov.l f19, [w1++] + mov.l f20, [w1++] + mov.l f21, [w1++] + mov.l f22, [w1++] + mov.l f23, [w1++] + mov.l f24, [w1++] + mov.l f25, [w1++] + mov.l f26, [w1++] + mov.l f27, [w1++] + mov.l f28, [w1++] + mov.l f29, [w1++] + mov.l f30, [w1++] + mov.l f31, [w1++] + mov.l #RCOUNT, w2 + mov.l [w2], [w1++] + mov.l #CORCON, w2 + mov.l [w2], [w1++] + mov.l #MODCON, w2 + mov.l [w2], [w1++] + mov.l #XMODSRT, w2 + mov.l [w2], [w1++] + mov.l #XMODEND, w2 + mov.l [w2], [w1++] + mov.l #YMODSRT, w2 + mov.l [w2], [w1++] + mov.l #YMODEND, w2 + mov.l [w2], [w1++] + mov.l #XBREV, w2 + mov.l [w2], [w1++] + clr A + clr B + slac.l A, [W1++] + sac.l A, [W1++] + suac.l A, [W1++] + slac.l B, [W1++] + sac.l B, [W1++] + suac.l B, [W1++] + mov.l w15, [w1++] + mov.l w14, [w1++] + mov.l #SPLIM, w2 + mov.l [w2], [w1++] + + mov.sl #__kernel+20,w0 + mov.l [w0],w0 + mov.sl #__kernel,w1 + mov.l w0,[w1+8] + mov.l [w0+300],w0 + rcall __set_tls + + mov.l #__kernel, w0 + mov.l #0x8, w1 + add w0, w1, w1 + mov.l [w1], w2 + mov.l #0x28, w1 + add w2, w1, w1 + + mov.l [w1++], w8 + mov.l [w1++], w9 + mov.l [w1++], w10 + mov.l [w1++], w11 + mov.l [w1++], w12 + mov.l [w1++], w13 + mov.l [w1++], w14 + mov.l [w1++], f8 + mov.l [w1++], f9 + mov.l [w1++], f10 + mov.l [w1++], f11 + mov.l [w1++], f12 + mov.l [w1++], f13 + mov.l [w1++], f14 + mov.l [w1++], f15 + mov.l [w1++], f16 + mov.l [w1++], f17 + mov.l [w1++], f18 + mov.l [w1++], f19 + mov.l [w1++], f20 + mov.l [w1++], f21 + mov.l [w1++], f22 + mov.l [w1++], f23 + mov.l [w1++], f24 + mov.l [w1++], f25 + mov.l [w1++], f26 + mov.l [w1++], f27 + mov.l [w1++], f28 + mov.l [w1++], f29 + mov.l [w1++], f30 + mov.l [w1++], f31 + mov.l #RCOUNT, w2 + mov.l [w1++], [w2] + mov.l #CORCON, w2 + mov.l [w1++], [w2] + mov.l #MODCON, w2 + mov.l [w1++], [w2] + mov.l #XMODSRT, w2 + mov.l [w1++], [w2] + mov.l #XMODEND, w2 + mov.l [w1++], [w2] + mov.l #YMODSRT, w2 + mov.l [w1++], [w2] + mov.l #YMODEND, w2 + mov.l [w1++], [w2] + mov.l #XBREV, w2 + mov.l [w1++], [w2] + clr A + clr B + slac.l A, [W1++] + sac.l A, [W1++] + suac.l A, [W1++] + slac.l B, [W1++] + sac.l B, [W1++] + suac.l B, [W1++] + mov.l [w1++], w15 + mov.l [w1++], w14 + mov.l #SPLIM, w2 + mov.l [w1++], [w2] + + ulnk + pop.l f7 + pop.l f6 + pop.l f5 + pop.l f4 + pop.l f3 + pop.l f2 + pop.l f1 + pop.l f0 + mov.l [--w15], w7 + mov.l [--w15], w6 + mov.l [--w15], w5 + mov.l [--w15], w4 + mov.l [--w15], w3 + mov.l [--w15], w2 + mov.l [--w15], w1 + mov.l [--w15], w0 + pop.l fcr + pop.l fsr + pop RCOUNT + mov.l w0, [w15++] + mov.l sr, w0 + and #0xe0, w0 + mov.l [--w15], w0 + bra nz, 1f + mov.l w2, [w15++] + mov.l w1, [w15++] + mov.l w0, [w15++] + mov.l #_swap_working_set, w0 + mov.l [--w15], [w0++] + mov.l [--w15], [w0++] + mov.l [--w15], [w0] + mov.l [--w15], w1 + mov.l [--w15], w2 + mov.l w2, sr + mov.l w1, [w15++] + mov.l [w0--], w2 + mov.l [w0--], w1 + mov.l [w0], w0 + lnk #0x4 + 1: + nop + cp.l w0,#0 + bra z,.L1 + bset.b _INTCON1+1,#7 + retfie + + + +.L2: + mov.l [--w15], w8 + ulnk +.L1: + retfie + + + .section .text._arch_dspic_irq_clear,code + .align 4 + .global _arch_dspic_irq_clear ; export + .type _arch_dspic_irq_clear,@function +_arch_dspic_irq_clear: + + lnk #36 + mov.w _INTTREGbits,w0 + mov.sl #.LC0,w1 + repeat #9-1 + mov.l [w1++],[w14++] + sub.l #36,w14 + sub.l #36,w1 + and.l #(0x1ff&0xFFFF),w0 + sub.l w0,#9,w0 + lsr.l w0,#5,w1 + sl.l w1,#2,w1 + add.l w1,w14,w1 + mov.l [w1],w2 + and.l w0,#(0x1f&0x7F),w0 + movs.l #0x1,w1 + sl.l w1,w0,w0 + com.l w0,w0 + and.l w0,[w2],[w2] + ulnk + return diff --git a/arch/dspic/core/isr_wrapper.c b/arch/dspic/core/isr_wrapper.c deleted file mode 100644 index 6a083bc538f2b..0000000000000 --- a/arch/dspic/core/isr_wrapper.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2025, Microchip Technology Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include - -/* dsPIC33A interrtup exit routine. Will check if a context - * switch is required. If so, z_dspic_do_swap() will be called - * to affect the context switch - */ -static inline __attribute__((always_inline)) void z_dspic_exc_exit(void) -{ -#ifdef CONFIG_PREEMPT_ENABLED - if ((_current_cpu->nested == 0) && (_kernel.ready_q.cache != _current) && - !k_is_pre_kernel()) { - z_dspic_do_swap(); - } - -#endif /* CONFIG_PREEMPT_ENABLED */ -#ifdef CONFIG_STACK_SENTINEL - z_check_stack_sentinel(); -#endif /* CONFIG_STACK_SENTINEL */ - return; -} - -void __attribute__((interrupt)) _isr_wrapper(void) -{ -#ifdef CONFIG_TRACING_ISR - sys_trace_isr_enter(); -#endif /* CONFIG_TRACING_ISR */ - - _current_cpu->nested++; - int32_t irq_number = INTTREGbits.VECNUM - 9; - const struct _isr_table_entry *entry = &_sw_isr_table[irq_number]; - (entry->isr)(entry->arg); - _current_cpu->nested--; - -#ifdef CONFIG_TRACING_ISR - sys_trace_isr_exit(); -#endif /* CONFIG_TRACING_ISR */ - - z_dspic_exc_exit(); -} diff --git a/arch/dspic/core/reset0.S b/arch/dspic/core/reset0.S index b0126d5183f2e..2b32c3edb25ae 100644 --- a/arch/dspic/core/reset0.S +++ b/arch/dspic/core/reset0.S @@ -20,6 +20,7 @@ __start: ;; Initialize stack pointer and limit mov.l #__SP_init, w15 ; Stack pointer (W15) mov.l #__SPLIM_init, w14 ; Stack limit (W14) + mov.l w14, _SPLIM ;; Data initialization mov.l #__dinit_tbloffset, w0 diff --git a/arch/dspic/core/swap.c b/arch/dspic/core/swap.c index 32f329c76df33..f9fd0806381c0 100644 --- a/arch/dspic/core/swap.c +++ b/arch/dspic/core/swap.c @@ -11,6 +11,8 @@ #include #include "kswap.h" +int swap_working_set[NUM_TEMP_REGS]; + int arch_swap(unsigned int key) { #ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING diff --git a/arch/dspic/core/thread.c b/arch/dspic/core/thread.c index 2ab6d2861b5d1..2e547115f3962 100644 --- a/arch/dspic/core/thread.c +++ b/arch/dspic/core/thread.c @@ -54,3 +54,8 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, char *sta /*TODO: Need to handle splim properly*/ thread->callee_saved.splim = RAM_END; } + +int arch_coprocessors_disable(struct k_thread *thread) +{ + return -ENOTSUP; +} diff --git a/arch/dspic/include/kernel_arch_swap.h b/arch/dspic/include/kernel_arch_swap.h index cd2a1953297e9..1aafb4e448525 100644 --- a/arch/dspic/include/kernel_arch_swap.h +++ b/arch/dspic/include/kernel_arch_swap.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -28,6 +29,9 @@ extern "C" { #include "kswap.h" +#define NUM_TEMP_REGS 3 +extern int swap_working_set[NUM_TEMP_REGS]; + static inline __attribute__((always_inline)) void z_dspic_save_context(void) { /*Adjust stack for co-operative swap*/ @@ -42,6 +46,25 @@ static inline __attribute__((always_inline)) void z_dspic_save_context(void) "mov.l [--w15], w0\n\t" /*This unlink is needed to match esf*/ "ulnk\n\t" + /*Backup the working reg W0-W2*/ + "mov.l w2, [w15++]\n\t" + "mov.l w1, [w15++]\n\t" + "mov.l w0, [w15++]\n\t" + "mov.l #_swap_working_set, w0\n\t" + "mov.l [--w15], [w0++]\n\t" + "mov.l [--w15], [w0++]\n\t" + "mov.l [--w15], [w0]\n\t" + /*Format SR and LR as its from interrupt*/ + "mov.l [--w15], w1\n\t" + "mov.l sr, [w15++]\n\t" + "mov.l w1, [w15++]\n\t" + "mov.l [w0--], w2\n\t" + "mov.l [w0--], w1\n\t" + "mov.l [w0], w0\n\t" + "mov.l w0, [w15++]\n\t" + + "1:\n\t" + "mov.l [--w15], w0\n\t" "push RCOUNT\n\t" "push.l fsr\n\t" "push.l fcr\n\t" @@ -53,7 +76,6 @@ static inline __attribute__((always_inline)) void z_dspic_save_context(void) "mov.l w5, [w15++]\n\t" "mov.l w6, [w15++]\n\t" "mov.l w7, [w15++]\n\t" - "mov.l w8, [w15++]\n\t" "push.l f0\n\t" "push.l f1\n\t" "push.l f2\n\t" @@ -62,13 +84,8 @@ static inline __attribute__((always_inline)) void z_dspic_save_context(void) "push.l f5\n\t" "push.l f6\n\t" "push.l f7\n\t" - "lnk #0x0\n\t" - /*in isr lnk is done after esf push*/ - "mov.l w0, [w15++]\n\t" - - /*In interrupt context*/ - "1:\n\t" - "mov.l [--w15], w0\n\t"); + "lnk #0x4\n\t"); + /*in isr lnk is done after esf push*/ /* Get the current thread callee_saved context * TODO: @@ -229,15 +246,6 @@ static inline __attribute__((always_inline)) void z_dspic_restore_context(void) /*pop exception/swap saved stack frame*/ __asm__ volatile( - /* Check context and only pop the - * esf if in thread context - */ - "mov.l w0, [w15++]\n\t" - "mov.l sr, w0\n\t" - "and #0xe0, w0\n\t" - "mov.l [--w15], w0\n\t" - "bra nz, 1f\n\t" - /*in isr the unlink is done before esf pop*/ "ulnk\n\t" /*Thread context*/ @@ -249,7 +257,6 @@ static inline __attribute__((always_inline)) void z_dspic_restore_context(void) "pop.l f2\n\t" "pop.l f1\n\t" "pop.l f0\n\t" - "mov.l [--w15], w8\n\t" "mov.l [--w15], w7\n\t" "mov.l [--w15], w6\n\t" "mov.l [--w15], w5\n\t" @@ -261,7 +268,34 @@ static inline __attribute__((always_inline)) void z_dspic_restore_context(void) "pop.l fcr\n\t" "pop.l fsr\n\t" "pop RCOUNT\n\t" - "lnk #0x0\n\t" + + /* Check context and only pop the + * esf if in thread context + */ + "mov.l w0, [w15++]\n\t" + "mov.l sr, w0\n\t" + "and #0xe0, w0\n\t" + "mov.l [--w15], w0\n\t" + "bra nz, 1f\n\t" + + /*Backup the working reg W0-W2*/ + "mov.l w2, [w15++]\n\t" + "mov.l w1, [w15++]\n\t" + "mov.l w0, [w15++]\n\t" + "mov.l #_swap_working_set, w0\n\t" + "mov.l [--w15], [w0++]\n\t" + "mov.l [--w15], [w0++]\n\t" + "mov.l [--w15], [w0]\n\t" + /*Format SR and LR as its from interrupt*/ + "mov.l [--w15], w1\n\t" + "mov.l [--w15], w2\n\t" + "mov.l w2, sr\n\t" + "mov.l w1, [w15++]\n\t" + "mov.l [w0--], w2\n\t" + "mov.l [w0--], w1\n\t" + "mov.l [w0], w0\n\t" + + "lnk #0x4\n\t" /*Interrupt context*/ "1:\n\t" @@ -271,11 +305,28 @@ static inline __attribute__((always_inline)) void z_dspic_restore_context(void) /* routine which swaps the context. Needs to be written in assembly */ static inline __attribute__((always_inline)) void z_dspic_do_swap(void) { + /* Switch to context 0 before starting context save and restore + * This Arch has 7 context and each has banked register sets for w0-w8 + * So in interrupt we are in ctx 1 and need to go to ctx 0 for tasks + */ + __asm__ volatile("CTXTSWP #0x0"); + z_dspic_save_context(); /*Switch to next task in queue*/ z_current_thread_set(_kernel.ready_q.cache); + /* It is expected to save current thread's pointer on z_tls_current + * variable because k_current_get() call will get the current thread's + * pointer from this variable if the CONFIG_CURRENT_THREAD_USE_TLS + * is enabled. In ztest k_thread_abort() was trying to abort the + * current thread. + */ +#ifdef CONFIG_CURRENT_THREAD_USE_TLS + /* Thread-local cache of current thread ID, set in z_thread_entry() */ + _set_tls((void *)_current->tls); +#endif + z_dspic_restore_context(); } diff --git a/boards/microchip/dspic33/dspic33a_curiosity/Kconfig.dspic33a_curiosity b/boards/microchip/dspic33/dspic33a_curiosity/Kconfig.dspic33a_curiosity index f0e2ba4c20ae4..2fe2d582a1f38 100644 --- a/boards/microchip/dspic33/dspic33a_curiosity/Kconfig.dspic33a_curiosity +++ b/boards/microchip/dspic33/dspic33a_curiosity/Kconfig.dspic33a_curiosity @@ -2,4 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_DSPIC33A_CURIOSITY + select SOC_P33AK512MPS512 if BOARD_DSPIC33A_CURIOSITY_P33AK512MPS512 select SOC_P33AK128MC106 if BOARD_DSPIC33A_CURIOSITY_P33AK128MC106 diff --git a/boards/microchip/dspic33/dspic33a_curiosity/board.cmake b/boards/microchip/dspic33/dspic33a_curiosity/board.cmake index 2138e0440d0bd..fcf825924f8a1 100644 --- a/boards/microchip/dspic33/dspic33a_curiosity/board.cmake +++ b/boards/microchip/dspic33/dspic33a_curiosity/board.cmake @@ -11,6 +11,11 @@ if(CONFIG_BOARD_DSPIC33A_CURIOSITY_P33AK128MC106) board_runner_args(ipecmd "--device=33AK128MC106" "--flash-tool=PKOB4") endif() +if(CONFIG_BOARD_DSPIC33A_CURIOSITY_P33AK512MPS512) + message(STATUS "device selected") + board_runner_args(ipecmd "--device=33AK512MPS512" "--flash-tool=PKOB4") +endif() + board_finalize_runner_args(ipecmd) set_property(GLOBAL PROPERTY BOARD_SUPPORTS_DEBUGGER TRUE) diff --git a/boards/microchip/dspic33/dspic33a_curiosity/board.yml b/boards/microchip/dspic33/dspic33a_curiosity/board.yml index 561db73fdf4a9..412a13838177c 100644 --- a/boards/microchip/dspic33/dspic33a_curiosity/board.yml +++ b/boards/microchip/dspic33/dspic33a_curiosity/board.yml @@ -5,3 +5,4 @@ board: socs: - name: p33ak128mc106 - name: p33ak256mc506 + - name: p33ak512mps512 diff --git a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106.dts b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106.dts index 1ae8e10b0a118..ff347435c1628 100644 --- a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106.dts +++ b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106.dts @@ -5,6 +5,7 @@ /dts-v1/; #include "p33ak128mc106.dtsi" +#include / { model = "Microchip dsPIC33A Curiosity Platform Development Board"; @@ -13,12 +14,62 @@ chosen { zephyr,flash = &flash0; zephyr,sram = &sram0; - zephyr,serial = &uart1; - zephyr,console = &uart1; + zephyr,serial = &uart0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + uart,passthrough = &uart1; + }; + + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&gpioc 3 GPIO_ACTIVE_LOW>; + label = "P28 LED0"; + }; + led1: led_1 { + gpios = <&gpioc 4 GPIO_ACTIVE_LOW>; + label = "P30 LED1"; + }; + led2: led_2 { + gpios = <&gpioc 5 GPIO_ACTIVE_LOW>; + label = "P32 LED2"; + }; + led3: led_3 { + gpios = <&gpioc 6 GPIO_ACTIVE_LOW>; + label = "P34 LED3"; + }; + led4: led_4 { + gpios = <&gpioc 7 GPIO_ACTIVE_LOW>; + label = "P36 LED4"; + }; + led5: led_5 { + gpios = <&gpioc 8 GPIO_ACTIVE_LOW>; + label = "P50 LED5"; + }; + led6: led_6 { + gpios = <&gpioc 9 GPIO_ACTIVE_LOW>; + label = "P52 LED6"; + }; + led7: led_7 { + gpios = <&gpioc 10 GPIO_ACTIVE_LOW>; + label = "P54 LED7"; + }; }; aliases { - uart-0 = &uart1; + uart-0 = &uart0; + uart-1 = &uart1; + uart-2 = &uart2; + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + led4 = &led4; + led5 = &led5; + led6 = &led6; + led7 = &led7; + }; }; @@ -33,6 +84,14 @@ status = "okay"; }; +&uart0 { + status = "okay"; +}; + &uart1 { status = "okay"; }; + +&uart2 { + status = "okay"; +}; diff --git a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106.yaml b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106.yaml index 153574ec0de35..f42e7658c50e5 100644 --- a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106.yaml +++ b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106.yaml @@ -9,6 +9,7 @@ flash: 128 supported: - uart - timer + - gpio testing: default: true vendor: microchip diff --git a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106_defconfig b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106_defconfig index cbfee96cec289..dbc0c387442ee 100644 --- a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106_defconfig +++ b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak128mc106_defconfig @@ -6,6 +6,7 @@ CONFIG_LOG_MODE_MINIMAL=y CONFIG_PRINTK=y CONFIG_CONSOLE=y CONFIG_STDOUT_CONSOLE=n +CONFIG_UART_INTERRUPT_DRIVEN=y # For LOG_MODE_MINIMAL using UART CONFIG_UART_CONSOLE=y @@ -27,7 +28,7 @@ CONFIG_SERIAL=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=8000000 # Configures the system tick rate to 1000 ticks per second (1 ms tick interval). -CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_SYS_CLOCK_TICKS_PER_SEC=10000 # Specifies a single-core configuration for the SoC. CONFIG_MP_MAX_NUM_CPUS=1 diff --git a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512.dts b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512.dts new file mode 100644 index 0000000000000..728e405e568c4 --- /dev/null +++ b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512.dts @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include "p33ak512mps512.dtsi" +#include + +/ { + model = "Microchip dsPIC33A Curiosity Platform Development Board"; + compatible = "microchip,dspic33a-criosity-p33ak512mps512"; + + chosen { + zephyr,flash = &flash0; + zephyr,sram = &sram0; + zephyr,serial = &uart1; + zephyr,console = &uart1; + }; + + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&gpioc 8 GPIO_ACTIVE_LOW>; + label = "P28 LED0"; + }; + led1: led_1 { + gpios = <&gpioc 9 GPIO_ACTIVE_LOW>; + label = "P30 LED1"; + }; + led2: led_2 { + gpios = <&gpioc 10 GPIO_ACTIVE_LOW>; + label = "P32 LED2"; + }; + led3: led_3 { + gpios = <&gpioc 11 GPIO_ACTIVE_LOW>; + label = "P34 LED3"; + }; + led4: led_4 { + gpios = <&gpioc 12 GPIO_ACTIVE_LOW>; + label = "P36 LED4"; + }; + led5: led_5 { + gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; + label = "P50 LED5"; + }; + led6: led_6 { + gpios = <&gpioc 14 GPIO_ACTIVE_LOW>; + label = "P52 LED6"; + }; + led7: led_7 { + gpios = <&gpioc 15 GPIO_ACTIVE_LOW>; + label = "P54 LED7"; + }; + }; + + aliases { + uart-0 = &uart1; + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + led4 = &led4; + led5 = &led5; + led6 = &led6; + led7 = &led7; + }; +}; + +&cpu0 { + clock-frequency = <8000000>; + status = "okay"; + cpu-power-states = <&idle>; +}; + +&timer1 { + clock-frequency = <8000000>; + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; diff --git a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512.yaml b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512.yaml new file mode 100644 index 0000000000000..b74779f1a2cff --- /dev/null +++ b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512.yaml @@ -0,0 +1,15 @@ +identifier: dspic33a_curiosity/p33ak512mps512 +name: EV74H48A EVB DSPIC33AK512MPS512 +type: mcu +arch: dspic +toolchain: + - xcdsc +ram: 64 +flash: 512 +supported: + - uart + - timer + - gpio +testing: + default: true +vendor: microchip diff --git a/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512_defconfig b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512_defconfig new file mode 100644 index 0000000000000..cbfee96cec289 --- /dev/null +++ b/boards/microchip/dspic33/dspic33a_curiosity/dspic33a_curiosity_p33ak512mps512_defconfig @@ -0,0 +1,38 @@ +# Copyright (c) 2025, Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_PRINTK=y +CONFIG_CONSOLE=y +CONFIG_STDOUT_CONSOLE=n + +# For LOG_MODE_MINIMAL using UART +CONFIG_UART_CONSOLE=y +CONFIG_LOG_PRINTK=n +CONFIG_EARLY_CONSOLE=y +CONFIG_SERIAL=y + +# for LOG_MODE_IMMEDIATE using UART +# Uncomment below if using LOG_MODE_IMMEDIATE instead +# CONFIG_UART_CONSOLE=y +# CONFIG_LOG_ALWAYS_RUNTIME=y +# CONFIG_EARLY_CONSOLE=y +# CONFIG_SERIAL=y + +# Enables support for GPIO drivers on the target platform. +# CONFIG_GPIO=y + +# Defines the system hardware clock frequency as 8 MHz. +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=8000000 + +# Configures the system tick rate to 1000 ticks per second (1 ms tick interval). +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +# Specifies a single-core configuration for the SoC. +CONFIG_MP_MAX_NUM_CPUS=1 + +# For XC-DSC toolchain the default check init script of zephyr will fail +# because of an extra prepended underscore on symbols generated, +# For this reason keeping it disabled +CONFIG_CHECK_INIT_PRIORITIES=n diff --git a/cmake/bintools/xcdsc/target.cmake b/cmake/bintools/xcdsc/target.cmake index 70f4029a1408e..778666990f044 100644 --- a/cmake/bintools/xcdsc/target.cmake +++ b/cmake/bintools/xcdsc/target.cmake @@ -4,7 +4,7 @@ find_program(CMAKE_OBJDUMP NAMES ${XCDSC_BIN_PREFIX}objdump PATHS ${TOOLCHAIN_HO find_program(CMAKE_READELF NAMES ${XCDSC_BIN_PREFIX}readelf PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_STRIP NAMES ${XCDSC_BIN_PREFIX}strip PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) # Archive Rules Setup -SET(CMAKE_C_ARCHIVE_CREATE " -q ") -SET(CMAKE_C_ARCHIVE_FINISH " -q ") +SET(CMAKE_C_ARCHIVE_CREATE " -q -mdfp=\"${DFP_ROOT}/xc16\"") +SET(CMAKE_C_ARCHIVE_FINISH " -q -mdfp=\"${DFP_ROOT}/xc16\"") # Include bin tool properties include(${ZEPHYR_BASE}/cmake/bintools/xcdsc/target_bintools.cmake) diff --git a/cmake/bintools/xcdsc/target_bintools.cmake b/cmake/bintools/xcdsc/target_bintools.cmake index c1f4ac2047fb7..956e8c3737de8 100644 --- a/cmake/bintools/xcdsc/target_bintools.cmake +++ b/cmake/bintools/xcdsc/target_bintools.cmake @@ -1,5 +1,5 @@ # Usage of the objcopy utility (aliased as elfconvert) for converting ELF binaries into other formats,such as hex, binary, etc. -set_property(TARGET bintools PROPERTY elfconvert_command ${CMAKE_OBJCOPY}) +set_property(TARGET bintools PROPERTY elfconvert_command ${CMAKE_OBJCOPY} -mdfp="${DFP_ROOT}/xc16") # List of format the tool supports for converting, for example, # GNU tools uses objectcopy, which supports the following: ihex, srec, binary set_property(TARGET bintools PROPERTY elfconvert_formats ihex srec binary) diff --git a/cmake/compiler/xcdsc/compiler_flags.cmake b/cmake/compiler/xcdsc/compiler_flags.cmake index 976a396460632..52475bc591880 100644 --- a/cmake/compiler/xcdsc/compiler_flags.cmake +++ b/cmake/compiler/xcdsc/compiler_flags.cmake @@ -19,10 +19,13 @@ set_compiler_property(PROPERTY linker_script -Wl,-T) set_compiler_property(PROPERTY save_temps -save-temps=obj) # Smart I/O conversion for format strings (safe printf optimizations) list(APPEND TOOLCHAIN_C_FLAGS -msmart-io=1) + # Disable SFR access warnings list(APPEND TOOLCHAIN_C_FLAGS -msfr-warn=off) # Disable instruction scheduling (for stability) list(APPEND TOOLCHAIN_C_FLAGS -fno-schedule-insns -fno-schedule-insns2) list(APPEND TOOLCHAIN_C_FLAGS -fno-omit-frame-pointer) +# list(APPEND TOOLCHAIN_C_FLAGS -mdfp="${DFP_ROOT}/xc16") +# list(APPEND TOOLCHAIN_ASM_FLAGS -mdfp="${DFP_ROOT}/xc16") # assembler compiler flags for imacros. The specific header must be appended by user. -set_property(TARGET asm PROPERTY imacros -imacros) \ No newline at end of file +set_property(TARGET asm PROPERTY imacros -imacros) diff --git a/cmake/compiler/xcdsc/generic.cmake b/cmake/compiler/xcdsc/generic.cmake index 7b5dd556de348..043f88a5fd6bd 100644 --- a/cmake/compiler/xcdsc/generic.cmake +++ b/cmake/compiler/xcdsc/generic.cmake @@ -1,8 +1,198 @@ set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR ${ARCH}) +# Find Microchip dsPIC33 DFP (MC/MP) for specified architectures by locating c30_device.info, +# preferring HOME packs over system installs, and extracting a clean DFP root +# (.../dsPIC33XX-YY_DFP/), regardless of deeper subfolders (e.g., xc16/bin/...). +# +# Usage: +# find_dspic33_dfp( +# OUT_INFO # output: full path to c30_device.info +# OUT_ROOT # output: DFP root (.../dsPIC33XX-YY_DFP/) +# [ARCHES ...] # default: AK CD CH +# [FAMILIES ...] # default: MC MP +# [ROOTS ...] # optional; HOME is always searched first +# [HINT_VERSION ] # optional preferred version (e.g., 1.1.109) +# ) +function(find_dspic33_dfp) + set(options) + set(oneValueArgs OUT_INFO OUT_ROOT HINT_VERSION) + set(multiValueArgs ARCHES FAMILIES ROOTS) + cmake_parse_arguments(FD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT FD_OUT_INFO OR NOT FD_OUT_ROOT) + message(FATAL_ERROR "find_dspic33_dfp: You must pass OUT_INFO and OUT_ROOT variable names.") + endif() + + # --- Defaults --- + if(NOT FD_ARCHES) + set(FD_ARCHES AK CD CH) + endif() + if(NOT FD_FAMILIES) + set(FD_FAMILIES MC MP) + endif() + + # Home path (works on Win/Linux) + set(_home "$ENV{HOME}") + if(WIN32 AND NOT _home) + set(_home "$ENV{USERPROFILE}") + file(TO_CMAKE_PATH "${_home}" _home) + endif() + + # Root search list: HOME first (highest priority), then system roots + set(_default_roots + "${_home}/.mchp_packs" + "/opt/microchip" "/opt/microchip/mplabx" + "C:/Program Files/Microchip" "C:/Program Files (x86)/Microchip" + ) + set(_search_roots "${_default_roots}") + if(FD_ROOTS) + # If caller passes ROOTS, append them after HOME so HOME still wins by default + list(APPEND _search_roots ${FD_ROOTS}) + endif() + + # Build case-insensitive regex for pack dir: dspic33[-_]_dfp + set(_alts "") + foreach(_a IN LISTS FD_ARCHES) + string(TOLOWER "${_a}" _al) + foreach(_f IN LISTS FD_FAMILIES) + string(TOLOWER "${_f}" _fl) + list(APPEND _alts "dspic33${_al}[-_]${_fl}_dfp") + endforeach() + endforeach() + string(REPLACE ";" "|" _alts_regex "${_alts}") + set(_pack_regex "(${_alts_regex})") + + # Collect candidates, tagging each with a priority rank (0 = HOME, 1 = system/others) + # We'll sort by (rank ASC, version/path NATURAL DESC) + set(_ranked_candidates) # entries like: "0|/full/path/to/c30_device.info" + foreach(_root IN LISTS _search_roots) + if(NOT _root OR NOT EXISTS "${_root}") + continue() + endif() + # Determine rank: 0 for home packs, 1 otherwise + set(_rank 1) + if(_root MATCHES "^${_home}(/|\\\\)\\.mchp_packs") + set(_rank 0) + endif() + + file(GLOB_RECURSE _found "${_root}/**/c30_device.info") + foreach(_p IN LISTS _found) + string(TOLOWER "${_p}" _pl) + if(_pl MATCHES "${_pack_regex}") + list(APPEND _ranked_candidates "${_rank}|${_p}") + endif() + endforeach() + endforeach() + + if(NOT _ranked_candidates) + message(FATAL_ERROR + "find_dspic33_dfp: No c30_device.info found for architectures {${FD_ARCHES}} " + "and families {${FD_FAMILIES}} under roots: ${_search_roots}") + endif() + + # Optional: version hint filter + if(FD_HINT_VERSION) + set(_hinted) + foreach(_rp IN LISTS _ranked_candidates) + string(REPLACE "|" ";" _parts "${_rp}") + list(GET _parts 1 _path) + if(_path MATCHES "/${FD_HINT_VERSION}(/|\\\\)") + list(APPEND _hinted "${_rp}") + endif() + endforeach() + if(_hinted) + set(_ranked_candidates "${_hinted}") + endif() + endif() + + # ---- Prefer rank 0; else fall back to rank 1 (Windows-safe) ---- + # Split into path-only buckets first + set(_r0_paths) + set(_r1_paths) + foreach(_entry IN LISTS _ranked_candidates) + string(REPLACE "|" ";" _parts "${_entry}") + list(GET _parts 0 _rk) + list(GET _parts 1 _pth) + if(_rk EQUAL 0) + list(APPEND _r0_paths "${_pth}") + else() + list(APPEND _r1_paths "${_pth}") + endif() + endforeach() + + # Sort each bucket naturally (DESC → newest-looking first) and pick + if(_r0_paths) + list(SORT _r0_paths COMPARE NATURAL ORDER DESCENDING) + list(GET _r0_paths 0 _best_path) + elseif(_r1_paths) + list(SORT _r1_paths COMPARE NATURAL ORDER DESCENDING) + list(GET _r1_paths 0 _best_path) + else() + message(FATAL_ERROR "find_dspic33_dfp: No ranked candidates after filtering.") + endif() + + # --- DFP root extraction --- + # Find "...///" inside the path and cut there. + string(TOLOWER "${_best_path}" _best_lc) + string(REGEX MATCH "(.*[/\\\\](dspic33[a-z0-9]+[-_][a-z0-9]+_dfp)[/\\\\]([^/\\\\]+))" _m "${_best_lc}") + if(_m) + string(REGEX REPLACE "^(.*[/\\\\](dspic33[a-z0-9]+[-_][a-z0-9]+_dfp)[/\\\\]([^/\\\\]+)).*$" "\\1" _dfp_root_lc "${_best_lc}") + string(LENGTH "${_dfp_root_lc}" _keep_len) + string(SUBSTRING "${_best_path}" 0 ${_keep_len} DFP_ROOT) + else() + # Fallback: strip known tails to version dir + set(_tmp "${_best_path}") + string(REGEX REPLACE "([/\\\\])xc16([/\\\\].*)?$" "" _tmp "${_tmp}") + string(REGEX REPLACE "([/\\\\])c30_device.info$" "" _tmp "${_tmp}") + set(DFP_ROOT "${_tmp}") + endif() + + # --- OUT_INFO should be the DIRECTORY containing c30_device.info (e.g., .../xc16/bin) --- + get_filename_component(_info_dir "${_best_path}" DIRECTORY) + + # Outputs + set(${FD_OUT_INFO} "${_info_dir}" PARENT_SCOPE) # directory only, no filename + set(${FD_OUT_ROOT} "${DFP_ROOT}" PARENT_SCOPE) +endfunction() + +if ("${BOARD_QUALIFIERS}" MATCHES "/p33ak128mc106" AND + "${BOARD}" MATCHES "dspic33a_curiosity") + set(TARGET_CPU "33AK128MC106") + find_dspic33_dfp( + OUT_INFO C30_DEVICE_INFO + OUT_ROOT DFP_ROOT + ARCHES AK + FAMILIES MC + ) +elseif("${BOARD_QUALIFIERS}" MATCHES "/p33ak512mps512" AND + "${BOARD}" MATCHES "dspic33a_curiosity") + set(TARGET_CPU "33AK512MPS512") + find_dspic33_dfp( + OUT_INFO C30_DEVICE_INFO + OUT_ROOT DFP_ROOT + ARCHES AK + FAMILIES MP + ) +endif() +message(STATUS "DFP file in ${C30_DEVICE_INFO}") +message(STATUS "DFP path ${DFP_ROOT}") + +set(ENV{C30_DEVICE_INFO} "${C30_DEVICE_INFO}") +set(ENV{DFP_ROOT} "${DFP_ROOT}") +set(ENV{TARGET_CPU} "${TARGET_CPU}") + +set(CMAKE_C_FLAGS "-D__XC_DSC__ -mdfp=\"${DFP_ROOT}/xc16\"" CACHE STRING "" FORCE) +set(CMAKE_ASM_FLAGS "-mdfp=\"${DFP_ROOT}/xc16\"" CACHE STRING "" FORCE) + +# Append to DTS preprocessor flags with DFP path +if(DEFINED DTS_EXTRA_CPPFLAGS AND NOT "${DTS_EXTRA_CPPFLAGS}" STREQUAL "") + list(APPEND DTS_EXTRA_CPPFLAGS "-mdfp=\"${DFP_ROOT}/xc16\"") +else() + set(DTS_EXTRA_CPPFLAGS "-mdfp=\"${DFP_ROOT}/xc16\"") +endif() # Find and validate the xc-dsc-gcc compiler binary find_program(CMAKE_C_COMPILER xc-dsc-gcc PATHS ${XCDSC_TOOLCHAIN_PATH}/bin/ NO_DEFAULT_PATH REQUIRED ) -set(CMAKE_C_FLAGS -D__XC_DSC__) + # Get compiler version execute_process( COMMAND ${CMAKE_C_COMPILER} --version diff --git a/cmake/compiler/xcdsc/target.cmake b/cmake/compiler/xcdsc/target.cmake index fbc7abedbaf9e..01921b9d22591 100644 --- a/cmake/compiler/xcdsc/target.cmake +++ b/cmake/compiler/xcdsc/target.cmake @@ -5,8 +5,7 @@ find_program(CMAKE_CXX_COMPILER xc-dsc-gcc PATHS ${XCDSC_TOOLCHAIN_PATH}/bin/ NO # Set assembler explicitly find_program(CMAKE_ASM_COMPILER xc-dsc-gcc PATHS ${XCDSC_TOOLCHAIN_PATH}/bin/ NO_DEFAULT_PATH ) # Target CPU (must match user platform) -set(TARGET_CPU "33AK128MC106") -list(APPEND TOOLCHAIN_C_FLAGS -mcpu=${TARGET_CPU}) +list(APPEND TOOLCHAIN_C_FLAGS "-mcpu=${TARGET_CPU}") # Picolibc and standard includes(if supported in toolchain) list(APPEND TOOLCHAIN_C_FLAGS -I${XCDSC_TOOLCHAIN_PATH}/include/picolibc diff --git a/cmake/linker/xcdsc/linker_flags.cmake b/cmake/linker/xcdsc/linker_flags.cmake index cb99a4775b360..bd6370f94a775 100644 --- a/cmake/linker/xcdsc/linker_flags.cmake +++ b/cmake/linker/xcdsc/linker_flags.cmake @@ -13,7 +13,7 @@ check_set_linker_property( ${LINKERFLAGPREFIX},--no-ivt # do not generate ivt or aivt # Check to create an interrupt function for unused vectors. - ${LINKERFLAGPREFIX},--no-gc-sections + ${LINKERFLAGPREFIX},--gc-sections # preserve all sections (do not garbage-collect unused code/data) ${LINKERFLAGPREFIX},--fill-upper=0 # zero-fill any gaps above defined sections @@ -25,5 +25,5 @@ check_set_linker_property( # Set picolib lib path from xc-dsc toolchain to link ${LINKERFLAGPREFIX}, -lc-pico-elf # link picolib from xc-dsc toolchain - + ${LINKERFLAGPREFIX}, -mdfp="${DFP_ROOT}/xc16" ) diff --git a/cmake/linker/xcdsc/target.cmake b/cmake/linker/xcdsc/target.cmake index 0f152caabaaec..f58b160a3cff6 100644 --- a/cmake/linker/xcdsc/target.cmake +++ b/cmake/linker/xcdsc/target.cmake @@ -24,6 +24,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define) -D_LINKER -D_ASM_LANGUAGE -D__XCDSC_LINKER_CMD__ + -mdfp="${DFP_ROOT}/xc16" -imacros ${AUTOCONF_H} -I${ZEPHYR_BASE}/include -imacros${ZEPHYR_BASE}/include/zephyr/linker/sections.h @@ -80,7 +81,6 @@ cmake_parse_arguments( endfunction(toolchain_ld_link_elf) # Finalize Link Execution Behaviour macro(toolchain_linker_finalize) - get_property(zephyr_std_libs TARGET linker PROPERTY lib_include_dir) get_property(link_order TARGET linker PROPERTY link_order_library) foreach(lib ${link_order}) get_property(link_flag TARGET linker PROPERTY ${lib}_library) diff --git a/cmake/toolchain/xcdsc/target.cmake b/cmake/toolchain/xcdsc/target.cmake index 59b4e22882b19..aa7bc1df72334 100644 --- a/cmake/toolchain/xcdsc/target.cmake +++ b/cmake/toolchain/xcdsc/target.cmake @@ -1 +1 @@ -set (ARCH dspic) \ No newline at end of file +set (ARCH dspic) diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 737662cfd36c5..3150d140cd88b 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -24,6 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_CC32XX gpio_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CMSDK_AHB gpio_cmsdk_ahb.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CY8C95XX gpio_cy8c95xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_DAVINCI gpio_davinci.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_DSPIC gpio_dspic.c) zephyr_library_sources_ifdef(CONFIG_GPIO_DW gpio_dw.c) zephyr_library_sources_ifdef(CONFIG_GPIO_EFINIX_SAPPHIRE gpio_efinix_sapphire.c) zephyr_library_sources_ifdef(CONFIG_GPIO_EMUL gpio_emul.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 978440cee2f60..0b8e3a52d6be6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -114,6 +114,7 @@ source "drivers/gpio/Kconfig.cmsdk_ahb" source "drivers/gpio/Kconfig.creg_gpio" source "drivers/gpio/Kconfig.cy8c95xx" source "drivers/gpio/Kconfig.davinci" +source "drivers/gpio/Kconfig.dspic" source "drivers/gpio/Kconfig.dw" source "drivers/gpio/Kconfig.efinix_sapphire" source "drivers/gpio/Kconfig.emul" diff --git a/drivers/gpio/Kconfig.dspic b/drivers/gpio/Kconfig.dspic new file mode 100644 index 0000000000000..b0f96cf652203 --- /dev/null +++ b/drivers/gpio/Kconfig.dspic @@ -0,0 +1,5 @@ +#Enable GPIO driver for dsPIC33A +config GPIO_DSPIC + bool "dsPIC33A GPIO driver" + help + Enable support for the dsPIC33A GPIO driver. diff --git a/drivers/gpio/gpio_dspic.c b/drivers/gpio/gpio_dspic.c new file mode 100644 index 0000000000000..b6e28834fb714 --- /dev/null +++ b/drivers/gpio/gpio_dspic.c @@ -0,0 +1,129 @@ +#define DT_DRV_COMPAT microchip_dspic_gpio + +#include +#include +#include +#include + +/* Offsets from PORTx base */ +#define TRIS_OFFSET ((uintptr_t)0x08u) +#define LAT_OFFSET ((uintptr_t)0x04u) +#define PORT_OFFSET ((uintptr_t)0x00u) +#define CNSTAT_OFFSET ((uintptr_t)0x0Cu) + +struct gpio_dspic_cfg { + uintptr_t base; +}; + +static int dspic_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_dspic_cfg *cfg = dev->config; + + /* TRIS offset */ + volatile uint16_t *tris = (void *)(cfg->base + TRIS_OFFSET); + + /* LAT offset */ + volatile uint16_t *lat = (void *)(cfg->base + LAT_OFFSET); + + /* Set initial level before direction */ + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { + *lat |= BIT(pin); + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { + *lat &= ~BIT(pin); + } else { + + /* Else statement added to clear MISRA warning */ + } + + /* Configure direction: TRIS bit = 0 for output, 1 for input */ + if ((flags & GPIO_OUTPUT) != 0) { + *tris &= ~BIT(pin); + } else { + *tris |= BIT(pin); + } + + return 0; +} + +static int dspic_port_toggle_bits(const struct device *dev, gpio_port_pins_t pin) +{ + const struct gpio_dspic_cfg *cfg = dev->config; + volatile uint16_t *lat = (void *)(cfg->base + LAT_OFFSET); + + /* Toggling the GPIO pin */ + *lat ^= pin; + + return 0; +} + +static int dspic_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + const struct gpio_dspic_cfg *cfg = dev->config; + volatile const uint16_t *port = (void *)(cfg->base + PORT_OFFSET); + + /* Fetch all values in port */ + *value = *port; + return 0; +} + +static int dspic_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_dspic_cfg *cfg = dev->config; + volatile uint16_t *lat = (void *)(cfg->base + LAT_OFFSET); + + /* Set bits in LAT register */ + *lat |= pins; + return 0; +} + +static int dspic_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_dspic_cfg *cfg = dev->config; + volatile uint16_t *lat = (void *)(cfg->base + LAT_OFFSET); + + /* Clear bits in LAT register */ + *lat &= ~pins; + return 0; +} + +static uint32_t dspic_get_pending_int(const struct device *dev) +{ + const struct gpio_dspic_cfg *cfg = dev->config; + volatile const uint16_t *cnstat = (void *)(cfg->base + CNSTAT_OFFSET); + + /* CNSTATx has the latched change status for each pin */ + return *cnstat; +} + +static int dspic_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_dspic_cfg *cfg = dev->config; + volatile uint16_t *lat = (void *)(cfg->base + LAT_OFFSET); + uint16_t tmp = *lat; + + tmp = (tmp & ~mask) | (value & mask); + *lat = tmp; + + return 0; +} + +static const struct gpio_driver_api gpio_dspic_api = { + .pin_configure = dspic_pin_configure, + .port_toggle_bits = dspic_port_toggle_bits, + .port_get_raw = dspic_port_get_raw, + .port_set_bits_raw = dspic_port_set_bits_raw, + .port_clear_bits_raw = dspic_port_clear_bits_raw, + .get_pending_int = dspic_get_pending_int, + .port_set_masked_raw = dspic_set_masked_raw, +}; + +/* Create instances from DT */ +#define GPIO_DSPIC_INIT(inst) \ + static const struct gpio_dspic_cfg gpio_dspic_cfg_##inst = { \ + .base = DT_INST_REG_ADDR(inst), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, NULL, &gpio_dspic_cfg_##inst, POST_KERNEL, \ + CONFIG_GPIO_INIT_PRIORITY, &gpio_dspic_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_DSPIC_INIT) diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 169c36f460af7..ab2b0553ee0db 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -57,6 +57,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_SY1XX pinctrl_sy1xx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_REALTEK_RTS5912 pinctrl_realtek_rts5912.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_20X_30X_AFIO pinctrl_wch_20x_30x_afio.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_WCH_00X_AFIO pinctrl_wch_00x_afio.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_MCHP_DSPIC33 pinctrl_mchp_dspic33.c) add_subdirectory(renesas) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index cd39637c2f6e6..7eedf0e0a082b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -87,6 +87,7 @@ source "drivers/pinctrl/Kconfig.sy1xx" source "drivers/pinctrl/Kconfig.realtek_rts5912" source "drivers/pinctrl/Kconfig.wch_20x_30x_afio" source "drivers/pinctrl/Kconfig.wch_00x_afio" +source "drivers/pinctrl/Kconfig.dspic33" rsource "renesas/Kconfig" diff --git a/drivers/pinctrl/Kconfig.dspic33 b/drivers/pinctrl/Kconfig.dspic33 new file mode 100644 index 0000000000000..06951815dc51e --- /dev/null +++ b/drivers/pinctrl/Kconfig.dspic33 @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_MCHP_DSPIC33 + bool "Pin controller driver for Microchip dsPIC33 MCUs" + default y + depends on DT_HAS_MICROCHIP_DSPIC33_PINCTRL_ENABLED + help + Enable the pin controller driver for Microchip dsPIC33 MCUs. diff --git a/drivers/pinctrl/pinctrl_mchp_dspic33.c b/drivers/pinctrl/pinctrl_mchp_dspic33.c new file mode 100644 index 0000000000000..18d02a9a4fef8 --- /dev/null +++ b/drivers/pinctrl/pinctrl_mchp_dspic33.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025, Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define DT_DRV_COMPAT microchip_dspic33_pinctrl + +#define MCHP_P33AK128MC106_GET_PORT_ADDR_OR_NONE(nodelabel) \ + IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \ + (DT_REG_ADDR(DT_NODELABEL(nodelabel)))) + +static int pinctrl_configure_pin(pinctrl_soc_pin_t soc_pin) +{ + volatile uint32_t port; + volatile uint32_t pin; + volatile uint32_t func; + int ret = 0; + + /* GPIO port addresses */ + static const uint32_t gpios[] = { + MCHP_P33AK128MC106_GET_PORT_ADDR_OR_NONE(gpioa), + MCHP_P33AK128MC106_GET_PORT_ADDR_OR_NONE(gpiob), + MCHP_P33AK128MC106_GET_PORT_ADDR_OR_NONE(gpioc), + MCHP_P33AK128MC106_GET_PORT_ADDR_OR_NONE(gpiod), + }; + + port = DSPIC33_PINMUX_PORT(soc_pin.pinmux); + pin = DSPIC33_PINMUX_PIN(soc_pin.pinmux); + func = DSPIC33_PINMUX_FUNC(soc_pin.pinmux); + + if (gpios[port] != 0U) { + + if ((func & 0xFF00U) == 0U) { + /* Output Remappable functionality pins */ + volatile uint32_t reg_shift = + (((pin - 1U) < 4U) ? (0U) : ((pin - 1U) / 4U)); + volatile uint32_t reg_index = pin % 4U; + volatile uint32_t RPORx_BASE = gpios[0] + OFFSET_RPOR; + + func = (func << (reg_index * 8u)); + volatile uint32_t *RPORx = + (void *)(RPORx_BASE + (port * 0x10U) + (reg_shift * 4U)); + *RPORx |= func; + + /* Setting latch bit */ + volatile uint32_t *latch = (void *)(gpios[port] + OFFSET_LATCH); + *latch |= (1U << pin); + + /* Setting TRIS bit*/ + volatile uint32_t *tris = (void *)(gpios[port] + OFFSET_TRIS); + *tris &= ~(1U << pin); + + /* setting ANSEl bit */ + if ((port == PORT_A) || (port == PORT_B)) { + volatile uint32_t *ansel = + (void *)(gpios[0] + OFFSET_ANSEL + (port * 0x24U)); + *ansel &= ~(1U << pin); + } + + } else { + /* Input Remappable functionality pins */ + volatile int pin_rpin = (port * 0x10U) + pin + 1U; + volatile uint8_t *RPINx = (void *)(DSPIC33_PINMUX_FUNC(soc_pin.pinmux)); + *RPINx |= pin_rpin; + + /* setting ANSEl bit */ + if ((port == PORT_A) || (port == PORT_B)) { + volatile uint32_t *ansel = + (void *)(gpios[0] + OFFSET_ANSEL + (port * 0x24U)); + *ansel &= ~(1U << pin); + } + } + } else { + ret = -EINVAL; + } + + return 0; +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + int ret = 0; + + for (uint8_t i = 0U; i < pin_cnt; i++) { + ret = pinctrl_configure_pin(pins[i]); + } + + return ret; +} diff --git a/drivers/serial/Kconfig.dspic_uart b/drivers/serial/Kconfig.dspic_uart index bf582fb128c66..f97564d98aa9f 100644 --- a/drivers/serial/Kconfig.dspic_uart +++ b/drivers/serial/Kconfig.dspic_uart @@ -1,10 +1,11 @@ # Copyright (c) 2025, Microchip Technology Inc. # SPDX-License-Identifier: Apache-2.0 - config UART_DSPIC bool "dsPIC33A UART driver" default y select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + select PINCTRL help Enable support for the dsPIC33A UART driver. diff --git a/drivers/serial/uart_dspic.c b/drivers/serial/uart_dspic.c index c8f1542012669..861a4bf1de927 100644 --- a/drivers/serial/uart_dspic.c +++ b/drivers/serial/uart_dspic.c @@ -7,8 +7,10 @@ #include #include #include +#include #include #include +#include #ifndef _ASMLANGUAGE #include @@ -16,28 +18,266 @@ #define DT_DRV_COMPAT microchip_dspic33_uart -#define OFFSET_MODE 0x00U -#define OFFSET_STA 0x04U -#define OFFSET_TXREG 0x10U -#define OFFSET_BRG 0x08U -#define OFFSET_RXREG 0x0CU -#define BIT_UTXEN 0x00000020U -#define BIT_URXEN 0x00000010U -#define BIT_UARTEN 0x00008000U -#define BIT_TXBF 0x00100000U -#define BIT_RXBE 0x00020000U -#define FRACTIONAL_BRG 0x8000000U - -#define CALCULATE_BRG(baudrate) \ - ((ceil(((double)(sys_clock_hw_cycles_per_sec())) / ((double)(2U * (baudrate)))))) -const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(uart1)); +/* UART Register Offsets */ +#define UART_MODE (0x00U) /* Offset for UART Mode register */ +#define OFFSET_STA (0x04U) /* Offset for UART Status register */ +#define OFFSET_BRG (0x08U) /* Offset for Baud Rate Generator register */ +#define OFFSET_RXREG (0x0CU) /* Offset for UART Receive register */ +#define OFFSET_TXREG (0x10U) /* Offset for UART Transmit register */ + +/* UART Control Bits */ +#define BIT_UTXEN (0x00000020U) /* UART Transmit Enable bit mask */ +#define BIT_URXEN (0x00000010U) /* UART Receive Enable bit mask */ +#define BIT_UARTEN (0x00008000U) /* UART Module Enable bit mask */ +#define BIT_TXBF (0x00100000U) /* UART Transmit Buffer Full status */ +#define BIT_TXBE (0x00200000U) /* UART TX buffer empty status bit mask */ +#define BIT_RXBF (0x00010000U) /* UART RX buffer full bit */ +#define BIT_RXBE (0x00020000U) /* UART Receive Buffer Empty status */ +#define ERR_IRQ_ENABLE (0x00007F00U) /* UART Error interrupts enable mask */ +#define ERR_IRQ_CLEAR (0x00000017U) /* UART Error interrupts flag clear mask */ +#define FRACTIONAL_BRG (0x08000000U) /* Fractional Baud Rate Generator enable */ + +/* Interrupt Level Select Bits */ +#define BIT_UxTXWM (0x00000000U) /* UART TX interrupt level select bit */ +#define BIT_UxRXWM (0x00000000U) /* UART RX interrupt level select bit */ + +/* Generic Masks */ +#define BIT_MASK_RCVR (0xFFU) /* Mask for receiver buffer */ + static struct k_spinlock lock; struct uart_dspic_config { uint32_t base; uint32_t baudrate; +#ifdef CONFIG_PINCTRL + const struct pinctrl_dev_config *pcfg; +#endif +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + void (*irq_config_func)(const struct device *dev); + /* IRQ number */ + unsigned int rx_irq_num; + unsigned int tx_irq_num; + unsigned int err_irq_num; +#endif }; +static inline uint32_t CALCULATE_BRG(uint32_t baudrate) +{ + double sys_clk = (double)sys_clock_hw_cycles_per_sec(); + double divisor = (2.0 * (double)baudrate); + + /* Round up (ceil) as per formula */ + uint32_t brg = (uint32_t)ceil(sys_clk / divisor); + + return brg; +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +struct uart_dspic_data { + uart_irq_callback_user_data_t callback; + void *user_data; +}; + +static void uart_dspic_isr(const struct device *dev) +{ + struct uart_dspic_data *data = dev->data; + const struct uart_dspic_config *cfg = dev->config; + volatile uint32_t *UxSTA = (void *)(cfg->base + OFFSET_STA); + + /* RX interrupt flag set check */ + if ((bool)arch_dspic_irq_isset(cfg->rx_irq_num)) { + if ((bool)data->callback) { + data->callback(dev, data->user_data); + } + } + + /* TX interrupt flag set check */ + if ((bool)arch_dspic_irq_isset(cfg->tx_irq_num)) { + if ((bool)data->callback) { + data->callback(dev, data->user_data); + } + } + + /* ERR interrupt flag set check */ + if ((bool)arch_dspic_irq_isset(cfg->err_irq_num)) { + + /* Clear error interrupt flag in uart status register */ + *UxSTA &= ~ERR_IRQ_CLEAR; + if ((bool)data->callback) { + data->callback(dev, data->user_data); + } + } +} + +static void uart_dspic_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, + void *user_data) +{ + k_spinlock_key_t key; + struct uart_dspic_data *data = dev->data; + + /* Registering the callback function and user data */ + key = k_spin_lock(&lock); + data->callback = cb; + data->user_data = user_data; + k_spin_unlock(&lock, key); +} + +static void uart_dspic_irq_tx_enable(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + + key = k_spin_lock(&lock); + /* Enabling the UART transmit interrupt */ + irq_enable(cfg->tx_irq_num); + k_spin_unlock(&lock, key); +} + +static void uart_dspic_irq_tx_disable(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + + key = k_spin_lock(&lock); + /* Disabling the UART transmit interrupt */ + irq_disable(cfg->tx_irq_num); + k_spin_unlock(&lock, key); +} + +static void uart_dspic_irq_rx_enable(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + + key = k_spin_lock(&lock); + /* Enabling the UART receiver interrupt */ + irq_enable(cfg->rx_irq_num); + k_spin_unlock(&lock, key); +} + +static void uart_dspic_irq_rx_disable(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + + key = k_spin_lock(&lock); + /* Disabling the UART receiver interrupt */ + irq_disable(cfg->rx_irq_num); + k_spin_unlock(&lock, key); +} + +static void uart_dspic_irq_err_enable(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + + key = k_spin_lock(&lock); + /* Enabling the UART Error interrupt */ + irq_enable(cfg->err_irq_num); + k_spin_unlock(&lock, key); +} + +static void uart_dspic_irq_err_disable(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + + key = k_spin_lock(&lock); + /* Disabling the UART Error interrupt */ + irq_disable(cfg->err_irq_num); + k_spin_unlock(&lock, key); +} + +static int uart_dspic_irq_tx_ready(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + volatile uint32_t *UxSTA = (void *)(cfg->base + OFFSET_STA); + int ret; + + key = k_spin_lock(&lock); + /* Transmit buffer empty check */ + ret = (*UxSTA & BIT_TXBE) ? 1 : 0; + k_spin_unlock(&lock, key); + + return ret; +} + +static int uart_dspic_irq_rx_ready(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + volatile uint32_t *UxSTA = (void *)(cfg->base + OFFSET_STA); + int ret; + + key = k_spin_lock(&lock); + /* Receiver buffer not full check */ + ret = (*UxSTA & BIT_RXBF) ? 0 : 1; + k_spin_unlock(&lock, key); + + return ret; +} + +static int uart_dspic_irq_is_pending(const struct device *dev) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + int ret; + + /* Interrupt pending check */ + key = k_spin_lock(&lock); + ret = arch_dspic_irq_isset(cfg->rx_irq_num) | arch_dspic_irq_isset(cfg->tx_irq_num) | + arch_dspic_irq_isset(cfg->err_irq_num); + k_spin_unlock(&lock, key); + + return ret; +} + +static int uart_dspic_irq_update(const struct device *dev) +{ + (void)dev; + return 1; +} + +static int uart_dspic_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + volatile uint32_t *UxSTA = (void *)(cfg->base + OFFSET_STA); + volatile uint32_t *UxRXREG = (void *)(cfg->base + OFFSET_RXREG); + int num_read = 0; + + /* Transmitting data of size bytes */ + while ((num_read < size) && (!(*UxSTA & BIT_RXBE))) { + key = k_spin_lock(&lock); + rx_data[num_read] = *UxRXREG & BIT_MASK_RCVR; + num_read++; + k_spin_unlock(&lock, key); + } + + return num_read; +} + +static int uart_dspic_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) +{ + k_spinlock_key_t key; + const struct uart_dspic_config *cfg = dev->config; + volatile uint32_t *UxSTA = (void *)(cfg->base + OFFSET_STA); + volatile uint32_t *UxTXREG = (void *)(cfg->base + OFFSET_TXREG); + int num_sent = 0; + + /* Receiving data of size bytes */ + while ((num_sent < size) && (!(*UxSTA & BIT_TXBF))) { + key = k_spin_lock(&lock); + *UxTXREG = tx_data[num_sent]; + num_sent++; + k_spin_unlock(&lock, key); + } + + return num_sent; +} +#endif + static void uart_dspic_poll_out(const struct device *dev, unsigned char c) { k_spinlock_key_t key; @@ -79,39 +319,107 @@ static int uart_dspic_poll_in(const struct device *dev, unsigned char *c) static int uart_dspic_init(const struct device *dev) { - LATB = 0x0040UL; - TRISB = 0x0FBFUL; - ANSELA = 0x0FFFUL; - ANSELB = 0x033FUL; - - /* Assign U1TX to RP23 and U1RX to RP24*/ - _RP23R = 9; - _U1RXR = 24; const struct uart_dspic_config *cfg = dev->config; - volatile uint32_t *UxCON = (void *)(cfg->base + OFFSET_MODE); - - /* Setting the baudrate */ - *UxCON = FRACTIONAL_BRG; + volatile uint32_t *UxCON = (void *)(cfg->base); volatile uint32_t *UxBRG = (void *)(cfg->base + OFFSET_BRG); - *UxBRG = (uint32_t)CALCULATE_BRG(cfg->baudrate); + volatile uint32_t *UxSTA = (void *)(cfg->base + OFFSET_STA); + int ret = 0; + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret == 0) { + /* Setting the UART mode */ + *UxCON |= UART_MODE; + + /* Setting the baudrate */ + *UxCON |= FRACTIONAL_BRG; + *UxBRG |= CALCULATE_BRG(cfg->baudrate); + + /* Enable UART */ + *UxCON |= BIT_UARTEN; + *UxCON |= BIT_UTXEN; + *UxCON |= BIT_URXEN; + + /* Selecting the transmit and receive interrupt level bit */ + *UxSTA |= BIT_UxTXWM; + *UxSTA |= BIT_UxRXWM; + + /* Enabling the Error interrupts */ + *UxSTA |= ERR_IRQ_ENABLE; - /* Enable UART */ - *UxCON |= BIT_UARTEN | BIT_UTXEN | BIT_URXEN; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + if (cfg->irq_config_func != NULL) { + cfg->irq_config_func(dev); + } +#endif + } - return 0; + return ret; } static const struct uart_driver_api uart_dspic_api = { .poll_out = uart_dspic_poll_out, .poll_in = uart_dspic_poll_in, + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_dspic_fifo_fill, + .fifo_read = uart_dspic_fifo_read, + .irq_rx_enable = uart_dspic_irq_rx_enable, + .irq_rx_disable = uart_dspic_irq_rx_disable, + .irq_tx_enable = uart_dspic_irq_tx_enable, + .irq_tx_disable = uart_dspic_irq_tx_disable, + .irq_err_enable = uart_dspic_irq_err_enable, + .irq_err_disable = uart_dspic_irq_err_disable, + .irq_callback_set = uart_dspic_irq_callback_set, + .irq_tx_ready = uart_dspic_irq_tx_ready, + .irq_rx_ready = uart_dspic_irq_rx_ready, + .irq_is_pending = uart_dspic_irq_is_pending, + .irq_update = uart_dspic_irq_update, +#endif }; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#define UART_DSPIC_IRQ_HANDLER_DECLARE(inst) \ + static void uart_dspic_irq_config_##inst(const struct device *dev); + +#define UART_DSPIC_IRQ_HANDLER_DEFINE(inst) \ + static void uart_dspic_irq_config_##inst(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, 0, irq), \ + DT_INST_IRQ_BY_IDX(inst, 0, priority), uart_dspic_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, 1, irq), \ + DT_INST_IRQ_BY_IDX(inst, 1, priority), uart_dspic_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, 2, irq), \ + DT_INST_IRQ_BY_IDX(inst, 2, priority), uart_dspic_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(inst, 0, irq)); \ + irq_enable(DT_INST_IRQ_BY_IDX(inst, 1, irq)); \ + irq_enable(DT_INST_IRQ_BY_IDX(inst, 2, irq)); \ + } + +#define UART_DSPIC_IRQ_CONFIG_FUNC(inst) .irq_config_func = uart_dspic_irq_config_##inst, +#else +#define UART_DSPIC_IRQ_HANDLER_DECLARE(inst) +#define UART_DSPIC_IRQ_HANDLER_DEFINE(inst) +#define UART_DSPIC_IRQ_CONFIG_FUNC(inst) +#endif + #define UART_DSPIC_INIT(inst) \ + UART_DSPIC_IRQ_HANDLER_DECLARE(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ static const struct uart_dspic_config uart_dspic_config_##inst = { \ - .base = DT_REG_ADDR(DT_INST(inst, microchip_dspic33_uart)), \ - .baudrate = DT_PROP(DT_INST(inst, microchip_dspic33_uart), current_speed), \ + .base = DT_INST_REG_ADDR(inst), \ + .baudrate = DT_INST_PROP(inst, current_speed), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + UART_DSPIC_IRQ_CONFIG_FUNC(inst).rx_irq_num = DT_INST_IRQ_BY_IDX(inst, 0, irq), \ + .tx_irq_num = DT_INST_IRQ_BY_IDX(inst, 1, irq), \ + .err_irq_num = DT_INST_IRQ_BY_IDX(inst, 2, irq), \ }; \ - DEVICE_DT_INST_DEFINE(inst, uart_dspic_init, NULL, NULL, &uart_dspic_config_##inst, \ - PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_dspic_api); + static struct uart_dspic_data uart_dspic_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, uart_dspic_init, NULL, &uart_dspic_data_##inst, \ + &uart_dspic_config_##inst, PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, &uart_dspic_api); \ + UART_DSPIC_IRQ_HANDLER_DEFINE(inst) DT_INST_FOREACH_STATUS_OKAY(UART_DSPIC_INIT) diff --git a/drivers/timer/mchp_dspic33_timer.c b/drivers/timer/mchp_dspic33_timer.c index ec0470fe206d2..718544e09bd35 100644 --- a/drivers/timer/mchp_dspic33_timer.c +++ b/drivers/timer/mchp_dspic33_timer.c @@ -16,11 +16,12 @@ #include #define TIMER1_CYCLES_PER_TICK \ - ((sys_clock_hw_cycles_per_sec()) / \ - (2 * DT_INST_PROP(0, prescalar) * CONFIG_SYS_CLOCK_TICKS_PER_SEC)) + ((float)((sys_clock_hw_cycles_per_sec())) / \ + (float)((2 * DT_INST_PROP(0, prescalar) * CONFIG_SYS_CLOCK_TICKS_PER_SEC))) -#define MAX_TIMER_CLOCK_CYCLES 0xFFFFFFFFu +#define MAX_TIMER_CLOCK_CYCLES 0xFFFFFFFFU static struct k_spinlock lock; +static uint64_t total_cycles; uint8_t map_prescaler_to_bits(uint32_t val) { @@ -36,7 +37,7 @@ uint8_t map_prescaler_to_bits(uint32_t val) case 64: ret_val = 0b10; break; - case 128: + case 256: ret_val = 0b11; break; default: @@ -52,6 +53,8 @@ static void configure_timer1(void) /* clear timer control and timer count register */ T1CONbits.ON = 0; + + /* Select standard peripheral clock */ T1CONbits.TCS = 0; T1CONbits.TCKPS = map_prescaler_to_bits(DT_INST_PROP(0, prescalar)); TMR1 = 0; @@ -70,7 +73,14 @@ static void configure_timer1(void) */ uint32_t sys_clock_cycle_get_32(void) { - return TMR1; + uint32_t cycles; + k_spinlock_key_t key; + + key = k_spin_lock(&lock); + cycles = ((uint32_t)total_cycles + (uint32_t)TMR1); + k_spin_unlock(&lock, key); + + return cycles * 2U * DT_INST_PROP(0, prescalar); } uint32_t sys_clock_elapsed(void) @@ -90,9 +100,11 @@ uint32_t sys_clock_elapsed(void) * Call is made, the ticks elapsed is current timer1 count divided by * Number of cycles per tick */ - ticks_elapsed = (uint32_t)TMR1 < (uint32_t)TIMER1_CYCLES_PER_TICK - ? 0 - : (uint32_t)TMR1 / (uint32_t)TIMER1_CYCLES_PER_TICK; + ticks_elapsed = + (uint32_t)TMR1 < (uint32_t)TIMER1_CYCLES_PER_TICK + ? 0 + : (uint32_t)(TMR1 + ((uint32_t)TIMER1_CYCLES_PER_TICK / 2U)) / + ((uint32_t)TIMER1_CYCLES_PER_TICK); k_spin_unlock(&lock, key); } while (0); @@ -101,7 +113,7 @@ uint32_t sys_clock_elapsed(void) void sys_clock_set_timeout(int32_t ticks, bool idle) { - uint32_t next_count; + volatile uint32_t next_count; k_spinlock_key_t key; ARG_UNUSED(idle); @@ -109,7 +121,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) do { if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { - /* If it is not in tickles mode, no need to change the + /* if it is not in tickles mode, no need to change the * Timeout interval, it will periodically interrupt * At every tick */ @@ -121,6 +133,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) ? MAX_TIMER_CLOCK_CYCLES : (uint32_t)(ticks * TIMER1_CYCLES_PER_TICK); key = k_spin_lock(&lock); + total_cycles = total_cycles + (uint64_t)TMR1; /* clear the timer1 counter register and set the period register to the * New timeout value. This should be done with TIMER1 disabled @@ -131,7 +144,6 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) T1CONbits.ON = 1; k_spin_unlock(&lock, key); } while (0); - } /* Timer1 ISR */ @@ -150,8 +162,7 @@ static void timer1_isr(const void *arg) elapsed_ticks = (uint32_t)PR1 / (uint32_t)TIMER1_CYCLES_PER_TICK; key = k_spin_lock(&lock); - /* Clear the timer interrupt flag status bit*/ - IFS1bits.T1IF = 0; + total_cycles = total_cycles + (uint64_t)PR1; if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { /* If not in tickles mode set the interrupt to happen at the next diff --git a/dts/bindings/gpio/microchip,dspic-gpio.yaml b/dts/bindings/gpio/microchip,dspic-gpio.yaml new file mode 100644 index 0000000000000..e8919718fa603 --- /dev/null +++ b/dts/bindings/gpio/microchip,dspic-gpio.yaml @@ -0,0 +1,51 @@ +# microchip,dspic-gpio.yaml + +description: | + Group of GPIO-controlled LEDs. + + Each LED is defined in a child node of the gpio-leds node. + + Here is an example which defines three LEDs in the node /leds: + + / { + leds { + compatible = "gpio-leds"; + led_0 { + gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + }; + led_1 { + gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + }; + led_2 { + gpios = <&gpio1 15 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + }; + }; + + Above: + + - led_0 is pin 1 on gpio0. The LED is on when the pin is low, + and off when the pin is high. + - led_1 is pin 2 on gpio0. The LED is on when the pin is high, + and off when it is low. + - led_2 is pin 15 on gpio1. The LED is on when the pin is low, + and the pin's internal pull-up resistor should be enabled. + +compatible: "microchip,dspic-gpio" + +include: [gpio-controller.yaml] + +properties: + reg: + type: array + required: true + + gpio-controller: {} + + "#gpio-cells": + type: int + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/pinctrl/microchip,dspic33-pinctrl.yaml b/dts/bindings/pinctrl/microchip,dspic33-pinctrl.yaml new file mode 100644 index 0000000000000..0c251ed0a0804 --- /dev/null +++ b/dts/bindings/pinctrl/microchip,dspic33-pinctrl.yaml @@ -0,0 +1,26 @@ +description: | + Microchip dsPIC33 pin controller + +compatible: "microchip,dspic33-pinctrl" + +include: base.yaml + +properties: + reg: + required: true + + "#address-cells": + const: 1 + + "#size-cells": + const: 1 + +child-binding: + description: Pin configuration node + properties: + pinmux: + description: | + Pin multiplexing configuration for this group. + Multiple pins (like TX/RX) can be grouped inside one node. + required: true + type: int diff --git a/dts/bindings/serial/microchip,dspic33-uart.yaml b/dts/bindings/serial/microchip,dspic33-uart.yaml index be59014316e1c..6d220e9a050c2 100644 --- a/dts/bindings/serial/microchip,dspic33-uart.yaml +++ b/dts/bindings/serial/microchip,dspic33-uart.yaml @@ -1,19 +1,49 @@ -# microchip,dspic33-uart.yaml +# Copyright (c) 2025 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 description: Microchip dsPIC33 UART controller compatible: "microchip,dspic33-uart" -include: uart-controller.yaml +include: [uart-controller.yaml, pinctrl-device.yaml] properties: reg: required: true + type: array + description: Register address and size for the UART peripheral clock-frequency: type: int required: true + description: Clock frequency for the UART peripheral + + interrupts: + required: true + type: array + description: Interrupt specifiers for RX, TX, and error interrupts + + interrupt-names: + type: string-array + description: Interrupt names "rx", "tx", "err" + + interrupt-parent: + type: phandle + description: Parent interrupt controller + + current-speed: + required: true + type: int + description: Baud rate for the UART + + pinctrl-0: + required: true + description: Pin control group for default state + + pinctrl-names: + required: true + description: Pin control state names status: type: string - required: true + description: Device status diff --git a/dts/dspic/p33ak128mc106.dtsi b/dts/dspic/p33ak128mc106.dtsi index ad37b0c94029d..e8932fa332e8a 100644 --- a/dts/dspic/p33ak128mc106.dtsi +++ b/dts/dspic/p33ak128mc106.dtsi @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "zephyr/dt-bindings/pinctrl/mchp-p33ak128mc106-pinctrl.h" + / { model = "Microchip dsPIC33A Curiosity Platform Development Board"; compatible = "microchip,p33ak128mc106"; @@ -51,9 +53,9 @@ label = "SRAM"; }; - intc0: interrupt-controller@0 { + intc0: interrupt-controller@70 { compatible = "microchip,dspic33-intc"; - reg = <0x0 0x1>; + reg = <0x70 0x1>; interrupt-controller; #address-cells = <0>; #interrupt-cells = <2>; @@ -70,12 +72,108 @@ status = "okay"; }; - uart1: uart@1700 { + uart0: uart@1700 { + compatible = "microchip,dspic33-uart"; + reg = <0x1700 0x40>; + interrupts = <89 1>, <90 1>, <91 1>; + interrupt-names = "rx", "tx", "err"; + interrupt-parent = <&intc0>; + clock-frequency = <4000000>; + current-speed = <115200>; + pinctrl-0 = <&uart1_tx_default &uart1_rx_default>; + pinctrl-names = "default"; + status = "okay"; + }; + + uart1: uart@1740 { + compatible = "microchip,dspic33-uart"; + reg = <0x1740 0x40>; + interrupts = <93 1>, <94 1>, <95 1>; + interrupt-names = "rx", "tx", "err"; + interrupt-parent = <&intc0>; + clock-frequency = <4000000>; + current-speed = <115200>; + pinctrl-0 = <&uart2_tx_default &uart2_rx_default>; + pinctrl-names = "default"; + status = "okay"; + }; + + uart2: uart@1780 { compatible = "microchip,dspic33-uart"; - reg = <0x1700 0x28>; + reg = <0x1780 0x40>; + interrupts = <97 1>, <98 1>, <99 1>; + interrupt-names = "rx", "tx", "err"; + interrupt-parent = <&intc0>; clock-frequency = <4000000>; current-speed = <115200>; + pinctrl-0 = <&uart3_tx_default &uart3_rx_default>; + pinctrl-names = "default"; status = "okay"; }; + + pinctrl: pin-controller@200 { + compatible = "microchip,dspic33-pinctrl"; + reg = <0x0200 0x37D0>; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + + gpioa: gpio@200 { + compatible = "microchip,dspic-gpio"; + reg = <0x0200 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiob: gpio@214 { + compatible = "microchip,dspic-gpio"; + reg = <0x0214 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpioc: gpio@228 { + compatible = "microchip,dspic-gpio"; + reg = <0x0228 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiod: gpio@23C { + compatible = "microchip,dspic-gpio"; + reg = <0x023C 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + uart1_tx_default: uart1_tx_default { + pinmux = ; + }; + + uart1_rx_default: uart1_rx_default { + pinmux = ; + }; + + uart2_tx_default: uart2_tx_default { + pinmux = ; + }; + + uart2_rx_default: uart2_rx_default { + pinmux = ; + }; + + uart3_tx_default: uart3_tx_default { + pinmux = ; + }; + + uart3_rx_default: uart3_rx_default { + pinmux = ; + }; + }; + }; }; diff --git a/dts/dspic/p33ak512mps512.dtsi b/dts/dspic/p33ak512mps512.dtsi new file mode 100644 index 0000000000000..e833de64c15a9 --- /dev/null +++ b/dts/dspic/p33ak512mps512.dtsi @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2025, Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + model = "Microchip dsPIC33A Curiosity Platform Development Board"; + compatible = "microchip,p33ak128mc106"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "microchip,dsPIC33A"; + reg = <0>; + clock-frequency = <8000000>; + status = "okay"; + cpu-power-states = <&idle>; + }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000>; + }; + }; + }; + + aliases { + soc = &soc; + }; + + soc: soc { + compatible = "microchip,p33ak128mc106-soc"; + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@800000 { + compatible = "zephyr,flash"; + reg = <0x800000 0x80000>; + label = "FLASH"; + }; + + sram0: memory@4000 { + compatible = "zephyr,memory"; + reg = <0x4000 0x10000>; + label = "SRAM"; + }; + + intc0: interrupt-controller@0 { + compatible = "microchip,dspic33-intc"; + reg = <0x0 0x1>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + }; + + timer1: timer@1CE0 { + compatible = "microchip,dspic33-timer"; + reg = <0x1CE0 0xC>; + clock-frequency = <4000000>; + prescalar = <8>; + interrupt-parent = <&intc0>; + interrupts = <48 1>; + label = "TIMER_1"; + status = "okay"; + }; + + uart1: uart@1700 { + compatible = "microchip,dspic33-uart"; + reg = <0x1700 0x28>; + clock-frequency = <4000000>; + current-speed = <115200>; + status = "okay"; + }; + + gpioa: gpio@200 { + compatible = "microchip,dspic-gpio"; + reg = <0x200 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiob: gpio@214 { + compatible = "microchip,dspic-gpio"; + reg = <0x214 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpioc: gpio@228 { + compatible = "microchip,dspic-gpio"; + reg = <0x228 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiod: gpio@23C { + compatible = "microchip,dspic-gpio"; + reg = <0x23C 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpioe: gpio@250 { + compatible = "microchip,dspic-gpio"; + reg = <0x250 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiof: gpio@264 { + compatible = "microchip,dspic-gpio"; + reg = <0x264 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiog: gpio@278 { + compatible = "microchip,dspic-gpio"; + reg = <0x278 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpioh: gpio@28C { + compatible = "microchip,dspic-gpio"; + reg = <0x28C 0x20>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + }; +}; diff --git a/include/zephyr/arch/dspic/arch.h b/include/zephyr/arch/dspic/arch.h index 0d01867f5bdc0..fb2ddbd41f6a0 100644 --- a/include/zephyr/arch/dspic/arch.h +++ b/include/zephyr/arch/dspic/arch.h @@ -19,13 +19,13 @@ #define ARCH_STACK_PTR_ALIGN 4 -#define IRQ_KEY_ILR_IRQ_MASK 0x7 - -#define DSPIC_STATUS_DEFAULT 0 +#define STATUS_CTX_MASK 0x00070000 +#define IRQ_KEY_ILR_IRQ_MASK 0x7u #define DSPIC_PRIORITY_BITS 3u #define DSPIC_PRIORITY_WIDTH DSPIC_PRIORITY_BITS + 1u #define DSPIC_IRQ_PER_REG 8u #define DSPIC_PRIORITY_MASK ((1u << DSPIC_PRIORITY_BITS) - 1u) + #ifndef _ASMLANGUAGE #include #ifdef __cplusplus @@ -36,6 +36,8 @@ void arch_irq_enable(unsigned int irq); void arch_irq_disable(unsigned int irq); int arch_irq_is_enabled(unsigned int irq); void z_irq_spurious(const void *unused); +bool arch_dspic_irq_isset(unsigned int irq); +void z_dspic_enter_irq(int irq); /* dsPIC has no MMU, so device_map() is replaced with a direct assignment */ #define device_map(virt, phys, size, flags) *(virt) = (phys) @@ -79,27 +81,31 @@ static ALWAYS_INLINE void z_dspic_irq_priority_set(unsigned int irq, unsigned in static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) { - __builtin_write_DISICTL(key & IRQ_KEY_ILR_IRQ_MASK); - __builtin_enable_interrupts(); + if (key) { + __builtin_enable_interrupts(); + } } static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) { - return ((key & IRQ_KEY_ILR_IRQ_MASK) == IRQ_KEY_ILR_IRQ_MASK) ? false : true; + return key; } static ALWAYS_INLINE unsigned int arch_irq_lock(void) { volatile unsigned int key; - key = __builtin_write_DISICTL(IRQ_KEY_ILR_IRQ_MASK); + key = INTCON1bits.GIE; __builtin_disable_interrupts(); return key; } static ALWAYS_INLINE bool arch_is_in_isr(void) { - return ((INTTREGbits.VECNUM) ? (true) : (false)); + uint32_t status_reg; + + __asm__ volatile("mov.l sr, %0" : "=r"(status_reg)::); + return ((status_reg & STATUS_CTX_MASK) ? (true) : (false)); } static ALWAYS_INLINE void arch_nop(void) diff --git a/include/zephyr/arch/dspic/exception.h b/include/zephyr/arch/dspic/exception.h index f77c1e76f86c4..c8dd305294e3f 100644 --- a/include/zephyr/arch/dspic/exception.h +++ b/include/zephyr/arch/dspic/exception.h @@ -15,6 +15,7 @@ extern "C" { #endif struct arch_esf { + uint32_t SR; uint32_t PC; /* Program counter*/ uint32_t RCOUNT; /* repeat count register*/ uint32_t FSR; /* Floating point status register */ @@ -27,7 +28,6 @@ struct arch_esf { uint32_t W5; /* working register W5 */ uint32_t W6; /* working register W6 */ uint32_t W7; /* working register W7 */ - uint32_t W8; /* working register W8 */ uint32_t F0; /* Floating point register F0 */ uint32_t F1; /* Floating point register F1 */ uint32_t F2; /* Floating point register F2 */ diff --git a/include/zephyr/arch/dspic/linker.ld b/include/zephyr/arch/dspic/linker.ld index 99c689d432402..def7504fb2705 100644 --- a/include/zephyr/arch/dspic/linker.ld +++ b/include/zephyr/arch/dspic/linker.ld @@ -37,6 +37,12 @@ MEMORY /* Used by and documented in include/linker/intlist.ld */ IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K } +/* + * After adding gc-section option compiler was discarding __start symbol + * adding ENTRY directive avoid it from being discarded. + */ +ENTRY(__start) + SECTIONS { /* Start of the ROM-based sections */ @@ -166,6 +172,8 @@ SECTIONS } +PROVIDE(__isr_wrapper = __COMMONInterrupt); + /* ** ============== Equates for SFR Addresses ============= */ diff --git a/include/zephyr/dt-bindings/pinctrl/mchp-p33ak128mc106-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/mchp-p33ak128mc106-pinctrl.h new file mode 100644 index 0000000000000..61d5a2c4261e6 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/mchp-p33ak128mc106-pinctrl.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_MCHP_P33AK128MC106_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_MCHP_P33AK128MC106_PINCTRL_H_ + +#include + +/* Masks & Shifts */ +#define DSPIC33_PORT_MASK 0x3U /* 2 bits for 0-3 */ +#define DSPIC33_PORT_SHIFT 30 + +#define DSPIC33_PIN_MASK 0x3FU /* 6 bits for 0-47 */ +#define DSPIC33_PIN_SHIFT 24 + +#define DSPIC33_FUNC_MASK 0xFFFFFFU /* 24 bits for 0-511 */ +#define DSPIC33_FUNC_SHIFT 0 + +/* Encode: pack port, pin, function */ +#define DSPIC33_PINMUX(port, pin, func) \ + ((((port) & DSPIC33_PORT_MASK) << DSPIC33_PORT_SHIFT) | \ + (((pin) & DSPIC33_PIN_MASK) << DSPIC33_PIN_SHIFT) | \ + (((func) & DSPIC33_FUNC_MASK) << DSPIC33_FUNC_SHIFT)) + +/* Decode: extract port, pin, function */ +#define DSPIC33_PINMUX_PORT(pinmux) (((pinmux) >> DSPIC33_PORT_SHIFT) & DSPIC33_PORT_MASK) +#define DSPIC33_PINMUX_PIN(pinmux) (((pinmux) >> DSPIC33_PIN_SHIFT) & DSPIC33_PIN_MASK) +#define DSPIC33_PINMUX_FUNC(pinmux) (((pinmux) >> DSPIC33_FUNC_SHIFT) & DSPIC33_FUNC_MASK) + +#define OFFSET_RPOR 0x3780 +#define OFFSET_RPIN 0x3704 +#define OFFSET_LATCH 0x0004 +#define OFFSET_TRIS 0x0008 +#define OFFSET_ANSEL 0x3440 + +/* Port definitions */ +#define PORT_A 0 +#define PORT_B 1 +#define PORT_C 2 +#define PORT_D 3 + +/* Input Function Macros (for RPINRx register configuration) */ +#define INT1 0x3905 +#define INT2 0x3906 +#define INT3 0x3907 +#define INT4 0x3908 +#define T1CK 0x3909 +#define REFI1 0x390A +#define REFI2 0x390B +#define ICM1 0x390C +#define ICM2 0x390D +#define ICM3 0x390E +#define ICM4 0x390F +#define OCFA 0x3918 +#define OCFB 0x3919 +#define OCFC 0x391A +#define OCFD 0x391B +#define PCI8 0x391C +#define PCI9 0x391D +#define PCI10 0x391E +#define PCI11 0x391F +#define QEIA1 0x3920 +#define QEIB1 0x3921 +#define QEINDX1 0x3922 +#define QEIHOM1 0x3923 +#define U1RX 0x3928 +#define U1DSR 0x3929 +#define U2RX 0x392A +#define U2DSR 0x392B +#define SDI1 0x392C +#define SCK1IN 0x392D +#define SS1 0x392E +#define SDI2 0x3930 +#define SCK2IN 0x3931 +#define SS2 0x3932 +#define U3RX 0x3938 +#define U3DSR 0x3939 +#define SENT1 0x393E +#define SENT2 0x393F +#define SDI3 0x3940 +#define SCK3IN 0x3941 +#define SS3 0x3942 +#define PCI12 0x3948 +#define PCI13 0x3949 +#define PCI14 0x394A +#define PCI15 0x394B +#define PCI16 0x394C +#define PCI17 0x394D +#define PCI18 0x394E +#define ADTRIG31 0x394F +#define BISS1SL 0x3950 +#define BISS1GS 0x3951 +#define CLCINA 0x3954 +#define CLCINB 0x3955 +#define CLCINC 0x3956 +#define CLCIND 0x3957 +#define U1CTS 0x3958 +#define U2CTS 0x3959 +#define U3CTS 0x395A + +/* Output Function Macros (for RPnR register configuration) */ +#define DEFAULT_PORT 0x00 +#define PWM1H 0x01 +#define PWM1L 0x02 +#define PWM2H 0x03 +#define PWM2L 0x04 +#define PWM3H 0x05 +#define PWM3L 0x06 +#define PWM4H 0x07 +#define PWM4L 0x08 +#define U1TX 0x09 +#define U1RTS 0x0A +#define U2TX 0x0B +#define U2RTS 0x0C +#define SDO1 0x0D +#define SCK1OUT 0x0E +#define SS1OUT 0x0F +#define SDO2 0x10 +#define SCK2OUT 0x11 +#define SS2OUT 0x12 +#define SDO3 0x13 +#define SCK3OUT 0x14 +#define SS3OUT 0x15 +#define REFO1 0x16 +#define REFO2 0x17 +#define OCM1 0x18 +#define OCM2 0x19 +#define OCM3 0x1A +#define OCM4 0x1B +#define CMP1 0x20 +#define CMP2 0x21 +#define CMP3 0x22 +#define U3TX 0x24 +#define U3RTS 0x25 +#define PEVTA 0x2B +#define PEVTB 0x2C +#define QEICMP1 0x2D +#define CLC1OUT 0x2F +#define CLC2OUT 0x30 +#define PEVTC 0x33 +#define PEVTD 0x34 +#define PEVTE 0x35 +#define PEVTF 0x36 +#define PTG_TRIG24 0x37 +#define PTG_TRIG25 0x38 +#define SENT1OUT 0x39 +#define SENT2OUT 0x3A +#define BISS1MO 0x3F +#define BISS1MA 0x40 +#define CLC3OUT 0x41 +#define CLC4OUT 0x42 +#define U1DTRn 0x43 +#define U2DTRn 0x44 +#define U3DTRn 0x45 + +#endif diff --git a/kernel/include/kswap.h b/kernel/include/kswap.h index cff3efab6e90e..f25795d8c4181 100644 --- a/kernel/include/kswap.h +++ b/kernel/include/kswap.h @@ -206,7 +206,7 @@ static inline int z_swap_irqlock(unsigned int key) #ifdef CONFIG_SPIN_VALIDATE /* Refer to comment in do_swap() above for details */ -# ifndef CONFIG_ARM64 +# if !defined(CONFIG_ARM64) && !defined(CONFIG_DSPIC) __ASSERT(arch_irq_unlocked(key) || _current->base.thread_state & (_THREAD_DUMMY | _THREAD_DEAD), "Context switching while holding lock!"); diff --git a/kernel/thread.c b/kernel/thread.c index a23d4c2c36642..b7a8cfe221bc8 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -880,7 +880,7 @@ FUNC_NORETURN void k_thread_user_mode_enter(k_thread_entry_t entry, } #if defined(CONFIG_INIT_STACKS) && defined(CONFIG_THREAD_STACK_INFO) -#ifdef CONFIG_STACK_GROWS_UP +#if defined(CONFIG_STACK_GROWS_UP) && !defined(CONFIG_DSPIC) #error "Unsupported configuration for stack analysis" #endif /* CONFIG_STACK_GROWS_UP */ diff --git a/samples/basic/blinky/prj.conf b/samples/basic/blinky/prj.conf index 91c3c15b37d1e..fe2e63c01ec01 100644 --- a/samples/basic/blinky/prj.conf +++ b/samples/basic/blinky/prj.conf @@ -1 +1,5 @@ CONFIG_GPIO=y +CONFIG_PRINTK=y +CONFIG_RAM_CONSOLE=y +CONFIG_GPIO_DSPIC=y +CONFIG_STATIC_INIT_GNU=y diff --git a/samples/philosophers/src/main.c b/samples/philosophers/src/main.c index ddda605d5d21e..92d23af74fac0 100644 --- a/samples/philosophers/src/main.c +++ b/samples/philosophers/src/main.c @@ -59,8 +59,12 @@ #endif #ifndef NUM_PHIL +#if CONFIG_BOARD_DSPIC33A_CURIOSITY_P33AK128MC106 +#define NUM_PHIL 4 +#else #define NUM_PHIL 6 #endif +#endif #ifndef STATIC_OBJS #define STATIC_OBJS 0 diff --git a/samples/philosophers/src/phil_obj_abstract.h b/samples/philosophers/src/phil_obj_abstract.h index e749a3f8d4982..d8e898d5839e0 100644 --- a/samples/philosophers/src/phil_obj_abstract.h +++ b/samples/philosophers/src/phil_obj_abstract.h @@ -148,11 +148,28 @@ static fork_t forks[NUM_PHIL] = { #if STATIC_OBJS - &fork0, &fork1, &fork2, - &fork3, &fork4, &fork5, + &fork0, &fork1, + #if NUM_PHIL == 3 + &fork2, + #elif NUM_PHIL == 4 + &fork2, &fork3, + #elif NUM_PHIL == 5 + &fork2, &fork3, &fork4, + #elif NUM_PHIL == 6 + &fork2, &fork3, &fork4, &fork5, + #endif #else - (fork_t)&fork_objs[0], (fork_t)&fork_objs[1], (fork_t)&fork_objs[2], - (fork_t)&fork_objs[3], (fork_t)&fork_objs[4], (fork_t)&fork_objs[5], + (fork_t)&fork_objs[0], (fork_t)&fork_objs[1], + #if NUM_PHIL == 3 + (fork_t)&fork_objs[2], + #elif NUM_PHIL == 4 + (fork_t)&fork_objs[2], (fork_t)&fork_objs[3], + #elif NUM_PHIL == 5 + (fork_t)&fork_objs[2], (fork_t)&fork_objs[3], (fork_t)&fork_objs[4], + #elif NUM_PHIL == 6 + (fork_t)&fork_objs[2], (fork_t)&fork_objs[3], (fork_t)&fork_objs[4], + (fork_t)&fork_objs[5], + #endif #endif }; diff --git a/soc/microchip/dspic33/dspic33a/CMakeLists.txt b/soc/microchip/dspic33/dspic33a/CMakeLists.txt index fc4b7df67049a..0203d048ba0a4 100644 --- a/soc/microchip/dspic33/dspic33a/CMakeLists.txt +++ b/soc/microchip/dspic33/dspic33a/CMakeLists.txt @@ -1,5 +1,5 @@ zephyr_include_directories(.) -zephyr_include_directories(${XCDSC_TOOLCHAIN_PATH}/support/generic/h) +zephyr_include_directories(${DFP_ROOT}/support/generic/h) zephyr_sources_ifdef(CONFIG_PM power.c ) set(SOC_LINKER_SCRIPT diff --git a/soc/microchip/dspic33/dspic33a/Kconfig b/soc/microchip/dspic33/dspic33a/Kconfig index a51dc3592dced..d7b4cd98319d5 100644 --- a/soc/microchip/dspic33/dspic33a/Kconfig +++ b/soc/microchip/dspic33/dspic33a/Kconfig @@ -12,4 +12,3 @@ config SOC_SERIES_DSPIC33A select GEN_IRQ_VECTOR_TABLE select GEN_SW_ISR_TABLE select HAS_PM - select PM diff --git a/soc/microchip/dspic33/dspic33a/Kconfig.defconfig.p33ak512mps512 b/soc/microchip/dspic33/dspic33a/Kconfig.defconfig.p33ak512mps512 new file mode 100644 index 0000000000000..a0bb284458731 --- /dev/null +++ b/soc/microchip/dspic33/dspic33a/Kconfig.defconfig.p33ak512mps512 @@ -0,0 +1,37 @@ +# Copyright (c) 2025, Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_P33AK512MPS512 + +config SRAM_SIZE + default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_SRAM),0,K) + +config SRAM_BASE_ADDRESS + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_SRAM)) + +config FLASH_SIZE + default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_FLASH),0,K) + +config FLASH_BASE_ADDRESS + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_FLASH)) + +config MAIN_STACK_SIZE + default 128 + +config IDLE_STACK_SIZE + default 512 + +config MINIMAL_LIBC_SUPPORTED + bool + default n + +config NEWLIB_LIBC_SUPPORTED + bool + default n + +# Picolibc with C++ support in Zephyr SDK is handled by Zephyr SDK's own Kconfig. +config PICOLIBC_SUPPORTED + bool + default n + +endif # SOC_P33AK512MPS512 diff --git a/soc/microchip/dspic33/dspic33a/Kconfig.soc b/soc/microchip/dspic33/dspic33a/Kconfig.soc index 69cde09e0b3c1..ce681e7832048 100644 --- a/soc/microchip/dspic33/dspic33a/Kconfig.soc +++ b/soc/microchip/dspic33/dspic33a/Kconfig.soc @@ -11,6 +11,10 @@ select SOC_FAMILY_MICROCHIP_DSPIC33 config SOC_SERIES default "dspic33a" if SOC_SERIES_DSPIC33A +config SOC_P33AK512MPS512 + bool + select SOC_SERIES_DSPIC33A + config SOC_P33AK128MC106 bool select SOC_SERIES_DSPIC33A @@ -22,3 +26,4 @@ config SOC_P33AK256MC506 config SOC default "p33ak128mc106" if SOC_P33AK128MC106 default "p33ak256mc506" if SOC_P33AK256MC506 + default "p33ak512mps512" if SOC_P33AK512MPS512 diff --git a/soc/microchip/dspic33/dspic33a/pinctrl_soc.h b/soc/microchip/dspic33/dspic33a/pinctrl_soc.h new file mode 100644 index 0000000000000..32841c9d17488 --- /dev/null +++ b/soc/microchip/dspic33/dspic33a/pinctrl_soc.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025, Microchip Technology Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_DSPIC33A_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_DSPIC33A_PINCTRL_SOC_H_ + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pinctrl_soc_pin { + uint32_t pinmux; +} pinctrl_soc_pin_t; + +/* Extract pinmux from DT */ +#define Z_PINCTRL_DSPIC33_PINMUX_INIT(node_id) (uint32_t)(DT_PROP(node_id, pinmux)) + +/* For dsPIC33, no extra config bits for now → only pinmux */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ + {.pinmux = Z_PINCTRL_DSPIC33_PINMUX_INIT(DT_PROP_BY_IDX(node_id, state_prop, idx))}, + +/* Expand each pin in the list */ +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT)} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_DSPIC33A_PINCTRL_SOC_H_ */ diff --git a/soc/microchip/dspic33/soc.yml b/soc/microchip/dspic33/soc.yml index 7df418defe8dc..560781a1dafe8 100644 --- a/soc/microchip/dspic33/soc.yml +++ b/soc/microchip/dspic33/soc.yml @@ -3,7 +3,6 @@ family: series: - name: dspic33a socs: + - name: p33ak512mps512 - name: p33ak128mc106 - name: p33ak256mc506 - cpuclusters: - - name: cpu0 diff --git a/subsys/debug/thread_info.c b/subsys/debug/thread_info.c index bcd58211e3bb8..b042e82e2e6cc 100644 --- a/subsys/debug/thread_info.c +++ b/subsys/debug/thread_info.c @@ -85,6 +85,9 @@ const size_t _kernel_thread_info_offsets[] = { #elif defined(CONFIG_ARCH_POSIX) [THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread, callee_saved.thread_status), +#elif defined(CONFIG_DSPIC) + [THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread, + callee_saved.stack), #elif defined(CONFIG_XTENSA) /* Xtensa does not store stack pointers inside thread objects. * The registers are saved in thread stack where there is diff --git a/subsys/testsuite/include/zephyr/interrupt_util.h b/subsys/testsuite/include/zephyr/interrupt_util.h index cc2077d625de8..c4ad19ab725c4 100644 --- a/subsys/testsuite/include/zephyr/interrupt_util.h +++ b/subsys/testsuite/include/zephyr/interrupt_util.h @@ -224,6 +224,14 @@ static inline void trigger_irq(int irq) z_mips_enter_irq(irq); } +#elif defined(CONFIG_DSPIC) +extern void z_dspic_enter_irq(int); + +static inline void trigger_irq(int irq) +{ + z_dspic_enter_irq(irq); +} + #elif defined(CONFIG_CPU_CORTEX_R5) && defined(CONFIG_VIM) extern void z_vim_arm_enter_irq(int);