tabemann / zeptoforth

A not-so-small Forth for Cortex-M

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

NVIC_IPR_IP! and NVIC_IPR_IP@ broken on RP2040?

robzed opened this issue · comments

I have problems setting the interrupt priority registers.

RP2040 Datasheet says:

M0PLUS: NVIC_IPR0 Register
Offset: 0xe400
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest priority, and 3 is the lowest.
Note: Writing 1 to an NVIC_ICPR bit does not affect the active state of the corresponding interrupt.
These registers are only word-accessible

Note the last line.

  \ Set NVIC interrupt priority register field
  : NVIC_IPR_IP! ( priority u -- ) NVIC_IPR_Base + c! ;

  \ Get NVIC interrupt priority register field
  : NVIC_IPR_IP@ ( u -- priority ) NVIC_IPR_Base + c@ ;

I suspect using c! and c@ will be problematic.

This might do the job, although it's rather 'baroque' and overly complex for a Forth word... Perhaps there is a simpler method, or at least a way of refactoring it into a set of smaller words?

\ Set NVIC interrupt priority register field
\ From RP2040 datasheet page 77: "These registers are only word-accessible"
: NVIC_IPR_IP! ( priority u -- ) 
    dup 3 and 3 lshift ( priority u bit-offet ) 
    >R 3 invert and  ( priority cell-selector  )
    NVIC_IPR_Base + ( prority NVIC-aligned-addr )
    dup @ ( priority NVIC-aligned-addr contents32 )
    $FF R@ lshift bic ( priority NVIC-aligned-addr contents32-cleared )
    rot R> lshift or ( NVIC-algined-addr contents32-revised )
    swap ! ;

\ Get NVIC interrupt priority register field
\ From RP2040 datasheet page 77: "These registers are only word-accessible"
: NVIC_IPR_IP@ ( u -- priority )
    dup 3 and 3 lshift ( u bit-offet ) 
    >R 3 invert and  ( cell-selector  )
    NVIC_IPR_Base + ( NVIC-aligned-addr )
    @ ( contents32 )
    $FF R@ lshift and ( contents32-required )
    R> rshift
;

Thanks for catching this! Just tested it and byte-access indeed does not work for these registers.

I have come up with and tested the following code, and it appears to work (but who knows if zeptoforth will stop working once I add it and actually build rather than just exercising things from the REPL):

  begin-module interrupt-internal

    \ Create an address for a priority index
    : NVIC_IPR_IP_addr ( u -- addr ) 3 bic NVIC_IPR_Base + ;
    
    \ Create a bitshift for a priority index
    : NVIC_IPR_IP_shift ( u -- bitshift ) 3 and 3 lshift ;

    commit-flash
    
    \ Create a mask for a priority index
    : NVIC_IPR_IP_mask ( u -- mask ) NVIC_IPR_IP_shift $FF swap lshift ;

  end-module> import

  commit-flash
  
  \ Set NVIC interrupt priority register field
  : NVIC_IPR_IP! ( priority u -- )
    dup NVIC_IPR_IP_addr dup >r @ over NVIC_IPR_IP_mask bic
    swap NVIC_IPR_IP_shift rot $FF and swap lshift or r> !
  ;

  \ Get NVIC interrupt priority register field
  : NVIC_IPR_IP@ ( u -- priority )
    dup NVIC_IPR_IP_addr @ over NVIC_IPR_IP_mask and
    swap NVIC_IPR_IP_shift rshift
  ;

TEST RESULTS

Method

zeptoforth_full-1.1.0.2.uf2
Built for rp2040, version 1.1.0.2, on Sun Sep 17 08:40:41 PM CDT 2023


#include irq_info.fth
irq_priorities
: set_priority ( irq level0-3 -- )
  6 lshift swap NVIC_IPR_IP! 
;
irq_priorities
0 0 set_priority
1 1 set_priority
2 2 set_priority
3 3 set_priority

4 3 set_priority
5 2 set_priority
6 1 set_priority
7 0 set_priority

8 3 set_priority
#9 2 set_priority
#10 1 set_priority
#11 0 set_priority
irq_priorities

#12 3 set_priority
#13 1 set_priority
#14 2 set_priority
#15 2 set_priority

#16 1 set_priority
#17 2 set_priority
#18 3 set_priority
#19 0 set_priority

#20 1 set_priority
irq_priorities

0 NVIC_IPR_IP@ u.
interrupt import
$c0804000 NVIC_IPR_Base !
0 NVIC_IPR_IP@ u.
1 NVIC_IPR_IP@ u.
2 NVIC_IPR_IP@ u.
3 NVIC_IPR_IP@ u.
irq_priorities

Results

interrupt import  ok
decimal  ok
: .HEX ( n cnt -- ) HEX  <# 0 DO # LOOP #> TYPE DECIMAL ;  ok
: .B 0 2 .HEX ;  ok
: .H 0 4 .HEX ;  ok
: .L 0 8 .HEX ;  ok
: irq_priorities  ok
cr ." 0=high, 3=low" cr  ok
." mem man fault " SHPR1_PRI_4@ 6 rshift . cr  ok
." bus fault " SHPR1_PRI_5@ 6 rshift . cr  ok
." usage fault " SHPR1_PRI_6@ 6 rshift . cr  ok
." SVCall " SHPR2_PRI_11@ 6 rshift . cr  ok
." PendSV " SHPR3_PRI_14@ 6 rshift . cr  ok
." systick " SHPR3_PRI_15@ 6 rshift . cr  ok
32 0 do  ok
I ." IRQ" . I NVIC_IPR_IP@ 6 rshift . 3 spaces  ok
I 3 and 3 = IF cr THEN  ok
loop  ok
." Summary" cr  ok
NVIC_IPR_Base  ok
8 0 do  ok
." IRQ" I 4 * 3 + . I 4 * . space dup @ .L 4 + cr  ok
loop drop  ok
;  ok
: .bitpos ( data -- )  ok
32 0 do  ok
dup 1 rshift swap 1 and if ."  1" else ."  _" then  ok
loop  ok
drop  ok
;  ok
: irq_status  ok
cr ."         " #10 0 do SPACE SPACE loop #22 0 do I #10 / 1+ . loop  ok
cr ."         " #32 0 do I #10 MOD . loop  ok
cr ." pending" NVIC_ISPR_Base @  .bitpos  ok
cr ." enabled" NVIC_ISER_Base @  .bitpos  ok
cr ." NMI proc0 " $40004000 @ .L  ok
cr ." NMI proc1 " $40004004 @ .L  ok
cr  ok
cr ." 1=Low Level, 2=High Level, 4=Edge Low, 8=Edge High"  ok
cr ." INTR07-00 " $400140f0 @ .L \ .bitpos8  ok
cr ." INTR15-08 " $400140f4 @ .L \ .bitpos8  ok
cr ." INTR23-16 " $400140f8 @ .L \ .bitpos8  ok
cr ." INTR31-24 " $400140fc @ .L \ .bitpos8  ok
cr ." INTE07-00 " $40014100 @ .L \ .bitpos8  ok
cr ." INTE15-08 " $40014104 @ .L \ .bitpos8  ok
cr ." INTE23-16 " $40014108 @ .L \ .bitpos8  ok
cr ." INTE31-24 " $4001410c @ .L \ .bitpos8  ok
cr ." INTS07-00 " $40014120 @ .L \ .bitpos8  ok
cr ." INTS15-08 " $40014124 @ .L \ .bitpos8  ok
cr ." INTS23-16 " $40014128 @ .L \ .bitpos8  ok
cr ." INTS31-24 " $4001412c @ .L \ .bitpos8  ok
cr  ok
;  ok
: irq_source  ok
cr ." 0 TIMER_IRQ_0  6  XIP_IRQ    12 DMA_IRQ_1     18 SPI0_IRQ    24 I2C1_IRQ"  ok
cr ." 1 TIMER_IRQ_1  7  PIO0_IRQ_0 13 IO_IRQ_BANK0  19 SPI1_IRQ    25 RTC_IRQ"  ok
cr ." 2 TIMER_IRQ_2  8  PIO0_IRQ_1 14 IO_IRQ_QSPI   20 UART0_IRQ"  ok
cr ." 3 TIMER_IRQ_3  9  PIO1_IRQ_0 15 SIO_IRQ_PROC0 21 UART1_IRQ"  ok
cr ." 4 PWM_IRQ_WRAP 10 PIO1_IRQ_1 16 SIO_IRQ_PROC1 22 ADC_IRQ_FIFO"  ok
cr ." 5 USBCTRL_IRQ  11 DMA_IRQ_0  17 CLOCKS_IRQ    23 I2C0_IRQ"  ok
cr  ok
;  ok
irq_priorities 
0=high, 3=low
mem man fault 0 
bus fault 0 
usage fault 0 
SVCall 0 
PendSV 3 
systick 1 
IRQ0 0    IRQ1 0    IRQ2 0    IRQ3 0    
IRQ4 0    IRQ5 0    IRQ6 0    IRQ7 0    
IRQ8 0    IRQ9 0    IRQ10 0    IRQ11 0    
IRQ12 0    IRQ13 0    IRQ14 0    IRQ15 0    
IRQ16 0    IRQ17 0    IRQ18 0    IRQ19 0    
IRQ20 0    IRQ21 0    IRQ22 0    IRQ23 0    
IRQ24 0    IRQ25 0    IRQ26 0    IRQ27 0    
IRQ28 0    IRQ29 0    IRQ30 0    IRQ31 0    
Summary
IRQ3 0  00000000
IRQ7 4  00000000
IRQ11 8  00000000
IRQ15 12  00000000
IRQ19 16  00000000
IRQ23 20  00000000
IRQ27 24  00000000
IRQ31 28  00000000
 ok
: set_priority ( irq level0-3 -- )  ok
6 lshift swap NVIC_IPR_IP!  ok
;  ok
irq_priorities 
0=high, 3=low
mem man fault 0 
bus fault 0 
usage fault 0 
SVCall 0 
PendSV 3 
systick 1 
IRQ0 0    IRQ1 0    IRQ2 0    IRQ3 0    
IRQ4 0    IRQ5 0    IRQ6 0    IRQ7 0    
IRQ8 0    IRQ9 0    IRQ10 0    IRQ11 0    
IRQ12 0    IRQ13 0    IRQ14 0    IRQ15 0    
IRQ16 0    IRQ17 0    IRQ18 0    IRQ19 0    
IRQ20 0    IRQ21 0    IRQ22 0    IRQ23 0    
IRQ24 0    IRQ25 0    IRQ26 0    IRQ27 0    
IRQ28 0    IRQ29 0    IRQ30 0    IRQ31 0    
Summary
IRQ3 0  00000000
IRQ7 4  00000000
IRQ11 8  00000000
IRQ15 12  00000000
IRQ19 16  00000000
IRQ23 20  00000000
IRQ27 24  00000000
IRQ31 28  00000000
 ok
0 0 set_priority  ok
1 1 set_priority  ok
2 2 set_priority  ok
3 3 set_priority  ok
4 3 set_priority  ok
5 2 set_priority  ok
6 1 set_priority  ok
7 0 set_priority  ok
8 3 set_priority  ok
#9 2 set_priority  ok
#10 1 set_priority  ok
#11 0 set_priority  ok
irq_priorities 
0=high, 3=low
mem man fault 0 
bus fault 0 
usage fault 0 
SVCall 0 
PendSV 3 
systick 1 
IRQ0 0    IRQ1 1    IRQ2 2    IRQ3 3    
IRQ4 3    IRQ5 2    IRQ6 1    IRQ7 0    
IRQ8 3    IRQ9 2    IRQ10 1    IRQ11 0    
IRQ12 0    IRQ13 0    IRQ14 0    IRQ15 0    
IRQ16 0    IRQ17 0    IRQ18 0    IRQ19 0    
IRQ20 0    IRQ21 0    IRQ22 0    IRQ23 0    
IRQ24 0    IRQ25 0    IRQ26 0    IRQ27 0    
IRQ28 0    IRQ29 0    IRQ30 0    IRQ31 0    
Summary
IRQ3 0  C0804000
IRQ7 4  004080C0
IRQ11 8  004080C0
IRQ15 12  00000000
IRQ19 16  00000000
IRQ23 20  00000000
IRQ27 24  00000000
IRQ31 28  00000000
 ok
#12 3 set_priority  ok
#13 1 set_priority  ok
#14 2 set_priority  ok
#15 2 set_priority  ok
#16 1 set_priority  ok
#17 2 set_priority  ok
#18 3 set_priority  ok
#19 0 set_priority  ok
#20 1 set_priority  ok
irq_priorities 
0=high, 3=low
mem man fault 0 
bus fault 0 
usage fault 0 
SVCall 0 
PendSV 3 
systick 1 
IRQ0 0    IRQ1 1    IRQ2 2    IRQ3 3    
IRQ4 3    IRQ5 2    IRQ6 1    IRQ7 0    
IRQ8 3    IRQ9 2    IRQ10 1    IRQ11 0    
IRQ12 3    IRQ13 1    IRQ14 2    IRQ15 2    
IRQ16 1    IRQ17 2    IRQ18 3    IRQ19 0    
IRQ20 1    IRQ21 0    IRQ22 0    IRQ23 0    
IRQ24 0    IRQ25 0    IRQ26 0    IRQ27 0    
IRQ28 0    IRQ29 0    IRQ30 0    IRQ31 0    
Summary
IRQ3 0  C0804000
IRQ7 4  004080C0
IRQ11 8  004080C0
IRQ15 12  808040C0
IRQ19 16  00C08040
IRQ23 20  00000040
IRQ27 24  00000000
IRQ31 28  00000000
 ok
0 NVIC_IPR_IP@ u. 0  ok
interrupt import  ok
$c0804000 NVIC_IPR_Base !  ok
0 NVIC_IPR_IP@ u. 0  ok
1 NVIC_IPR_IP@ u. 64  ok
2 NVIC_IPR_IP@ u. 128  ok
3 NVIC_IPR_IP@ u. 192  ok
irq_priorities 
0=high, 3=low
mem man fault 0 
bus fault 0 
usage fault 0 
SVCall 0 
PendSV 3 
systick 1 
IRQ0 0    IRQ1 1    IRQ2 2    IRQ3 3    
IRQ4 3    IRQ5 2    IRQ6 1    IRQ7 0    
IRQ8 3    IRQ9 2    IRQ10 1    IRQ11 0    
IRQ12 3    IRQ13 1    IRQ14 2    IRQ15 2    
IRQ16 1    IRQ17 2    IRQ18 3    IRQ19 0    
IRQ20 1    IRQ21 0    IRQ22 0    IRQ23 0    
IRQ24 0    IRQ25 0    IRQ26 0    IRQ27 0    
IRQ28 0    IRQ29 0    IRQ30 0    IRQ31 0    
Summary
IRQ3 0  C0804000
IRQ7 4  004080C0
IRQ11 8  004080C0
IRQ15 12  808040C0
IRQ19 16  00C08040
IRQ23 20  00000040
IRQ27 24  00000000
IRQ31 28  00000000
 ok

Conclusion

Test results show that the NVIC_IPR_IP! and NVIC_IPR_IP@ perform as expected with no unexpected results.

Happy to close.