Hallo,
i have the following problem to solve:
an interrupt should be triggered when the frame-signal of a
SPI-interface changes from 0 to 1. If, at the time of enabling this
interrupt, the frame-signal is already high, the interrupt should be
triggered by software instead of the rising edge.
I am using int-structures representing the register-bits of EXTI and
other peripherals mapped to the according places within the
bit-banding-area of the micro. These are name XXXbbbits. I am also using
bit-structures which are representing the structures of their according
registers to manipulate two or more bits at a time. Those are called
XXXbits and are mapped to the registers original locations.
My SPI acts as a Slave.
I tried the following:
1 | #define TDXSPIClearFrameInt() EXTIbbbits.PR.PR4=EXTI_PR_INT_CLR
|
2 | #define TDXSPIDisableFrameInt() EXTIbbbits.IMR.MR4=EXTI_IMR_INT_DIS
|
3 | #define TDXSPIEnableFrameInt() EXTIbbbits.IMR.MR4=EXTI_IMR_INT_EN
|
4 | #define TDXSPIClearPendingFrameInt() NVIC_ClearPendingIRQ(EXTI4_IRQn)
|
5 | #define TDXSPISelectRisingFrameInt() EXTIbbbits.RTSR.TR4=EXTI_RTSR_RE_EN
|
6 | #define TDXSPIUnselectRisingFrameInt() EXTIbbbits.RTSR.TR4=EXTI_RTSR_RE_DIS
|
7 | #define TDXSPISelectFallingFrameInt() EXTIbbbits.FTSR.TR4=EXTI_FTSR_FE_EN
|
8 | #define TDXSPIUnselectFallingFrameInt() EXTIbbbits.FTSR.TR4=EXTI_FTSR_FE_DIS
|
9 | #define TDXSPICondRqFrameInt(cond) EXTIbbbits.SWIER.SWIER4=cond?EXTI_SWIER_INT_RQ:~EXTI_SWIER_INT_RQ
|
10 | #define TDXSPIRequestFrameInt() EXTIbbbits.SWIER.SWIER4=EXTI_SWIER_INT_RQ
|
11 |
|
12 | #define EXTI_IMR_INT_DIS 0u
|
13 | #define EXTI_IMR_INT_EN 1u
|
14 | #define EXTI_EMR_EVT_DIS 0u
|
15 | #define EXTI_EMR_EVT_EN 1u
|
16 | #define EXTI_RTSR_RE_DIS 0u
|
17 | #define EXTI_RTSR_RE_EN 1u
|
18 | #define EXTI_FTSR_FE_DIS 0u
|
19 | #define EXTI_FTSR_FE_EN 1u
|
20 | #define EXTI_SWIER_INT_RQ 1u
|
21 | #define EXTI_PR_INT_CLR 1u
|
22 |
|
23 |
|
24 | void TDXSPISetTimeOut(enum eTDXSPITimeOutIntSources Source)
|
25 | {
|
26 | // Set time-out-value, enable interrupt for retrigger
|
27 | // timer is not startet in case of RX or TX since we don't know when the TDX starts transmission
|
28 | // timer is started after reception of the first unit
|
29 | // timer-interrupt only used for checking FRAME-idle-time
|
30 | // FRAME-interrupt is used to start timer in case of TX and FRAME supervision
|
31 | // time-out occured when UIF-flag is set
|
32 | TDXSPIDisableFrameInt(); // disable FRAME-interrrupts
|
33 | TDXSPIUnselectRisingFrameInt(); // not sensitive to any edge
|
34 | TDXSPIUnselectFallingFrameInt();
|
35 | TDXSPIDisableTimerInt(); // disable timer-interruptss
|
36 | TDXSPIStopTimer(); // stop timer
|
37 | switch(Source)
|
38 | {
|
39 | case TDXSPITimeOutIntSource_SPIRX: // initialize timer to supervise time-out during reception
|
40 | <some initialization>
|
41 | break;
|
42 |
|
43 | case TDXSPITimeOutIntSource_SPITX: // initialize timer to supervise time-out during transmission
|
44 | <some other initialization>
|
45 | break;
|
46 |
|
47 | case TDXSPITimeOutIntSource_RDY: // initialize timer to supervise maximum response-time to RDY
|
48 | <some other initialization>
|
49 | break;
|
50 |
|
51 | case TDXSPITimeOutIntSource_FRAME: // initialize timer to supervise minimum idle-time of FRAME-signal
|
52 | TDXSPITimerReloadReg=TDXSPIFRMMINIDLE;
|
53 | TDXSPIUpdateTimer();
|
54 | TDXSPIClearTimerStatus();
|
55 | TDXSPIDEnableTimerInt(); // enable timer-INTs
|
56 | TDXSPISelectRisingFrameInt(); // Rising edge interrupt only
|
57 | TDXSPIClearFrameInt(); // clear pending INTs
|
58 | TDXSPIClearPendingFrameInt();
|
59 | if(TDXSPIFrameIsIdle()) // request Int manually if FRAME is already idle
|
60 | {
|
61 | TDXSPIRequestFrameInt();
|
62 | }
|
63 | TDXSPIEnableFrameInt(); // enable FRAME-INTs
|
64 | break;
|
Unfortunately, no interrupt is issued by software. The interrupt is
triggered only by hardware when the next positive edge occurs. But this
is one telegram to late.
If I exchange the last two commands, it runs ok:
1 | TDXSPIEnableFrameInt(); // enable FRAME-INTs
|
2 | if(TDXSPIFrameIsIdle()) // request Int manually if FRAME is already idle
|
3 | {
|
4 | TDXSPIRequestFrameInt();
|
5 | }
|
But, I ran into a race-condition when FRAME has its positive edge while
the TDXSPIEnableFrameInt() is executed. In this case, the interrupt is
triggered twice, first by hardware, than again by the if-clause. This
should not happen.
I have no Idea, why the pending-bit is not set, when I use the first
example. The only way I found, was to disable the intrerrupts either
globally or in the NVIC, which I dislike both.
Has anybody a better idea or an explanation, why the first example
doesn't work?
Thanks in advance
Gernot