在线时间104 小时
UID3338547
注册时间2017-1-28
NXP金币14
TA的每日心情 | 无聊 2021-12-29 19:06 |
---|
签到天数: 47 天 连续签到: 1 天 [LV.5]常住居民I
金牌会员
 
- 积分
- 1392
- 最后登录
- 2025-3-4
|
本帖最后由 day_day 于 2018-4-21 14:07 编辑
一无所知的时候就要看看官方的工程,以下内容是基于芯片手册第12章(第13章是pin group中断,是多个中断指向一个中断组),摸索了大概半个星期,终于在昨天找到了例程里面的外部中断工程。
本人用的函数库不是sdk(fsl开头的),而是lpc原本适配的chip库,这个库虽然不如sdk丰富,但胜在简单易懂,而且api手册也做得比较好。
chip库里面的外部中断例程是这个:
(一)用户手册中
12.3.1 Configure pins as pin interrupts or as inputs to the pattern match
engine
Follow these steps to configure pins as pin interrupts:
1. Determine the pins that serve as pin interrupts on the LPC5411x package. See the
data sheet for determining the GPIO port pin number associated with the package pin.
2. For each pin interrupt, program the GPIO port pin number from ports 0 and 1 into one
of the eight PINTSEL registers in the Input mux block.
Remark: The port pin number serves to identify the pin to the PINTSEL register. Any
function, including GPIO, can be assigned to this pin via IOCON.
3. Enable each pin interrupt in the NVIC.
Once the pin interrupts or pattern match inputs are configured, the pin interrupt detection
levels or the pattern match boolean expression can set up.
See Section 10.6.1 “Pin interrupt select registers” in the Input mux block for the PINTSEL
registers.
Remark: The inputs to the Pin interrupt select registers bypass the IOCON function
selection. They do not have to be selected as GPIO in IOCON. Make sure that no analog
function is selected on pins that are input to the pin interrupts.
稍微翻译一下:
12.3.1-将引脚配置为引脚中断(pin interrupts),或作为模式匹配输入模式
按照以下方式配置引脚中断(pin interrupts)。
1、确定LPC5411x板子上要设置为外部中断(pin interrupts或者说引脚中断)的引脚。查询数据手册来确定GPIO端口、引脚与LPC5411x板子上引脚的对应关系
2、对于每个引脚中断,把GPIO的端口(port 0、1)、引脚号输入到多路复用输出块里面的八个PINTSEL寄存器中。
注意:端口、引脚用于识别PINTSEL寄存器的引脚号。任何功能,包括GPIO,可以通过IOCON分配给这个引脚。
3、在NVIC里面使能每个引脚中断(pin interrupts)
一旦引脚中断(pin interrupts)或模式匹配(pattern match)输入被配置,引脚中断检测优先级(the pin interrupt detection
levels)或模式匹配布尔表达式(the pattern match boolean expression)可以设置。
请参阅多路复用输出块里面第10.6.1“引脚中断选择寄存器(the pin interrupt select registers)”。
注意:引脚中断选择寄存器(the pin interrupt select registers)的输入绕过了IOCON函数选择。它们不需要在IOCON中被选择为GPIO模式。确保这个涉资为引脚中断(pin interrupts)的引脚没有被选择为模拟输入输出。
引脚中断(pin interrupts)和模式匹配引擎的输入由多路复用输出块里面的引脚中断选择寄存器(the pin interrupt select registers)决定。
小结:可以看到,这里称这个类似外部中断的功能为引脚中断(pin interrupts),而下一章几个引脚并在一起的中断称为GPIO组中断(gpio group interrupt)。
(二)pin interrupt相应寄存器- ISEL(R/W):Pin Interrupt Mode register;设置中断模式
- IENR(R/W):Pin interrupt level or rising edge interrupt enable register;设置该引脚中断上升边沿敏感/低电平敏感
- SIENR(W):Pin interrupt level or rising edge interrupt enable set register;让引脚中断上升边沿敏感/低电平敏感(设置这个寄存器其实就是往IENR里面写1,感觉有些多此一举)
- CIENR(W):Pin interrupt level or rising edge interrupt enable clear register;不让引脚中断上升边沿敏感/低电平敏感(设置这个寄存器其实就是往IENR里面写0,感觉有些多此一举)
- IENF(R/W):Pin interrupt active level or falling edge interrupt enable register;设置该引脚中断下降边沿敏感/高电平敏感
- SIENF(W):Pin interrupt active level or falling edge interrupt set register;让引脚中断下降边沿敏感/高电平敏感(设置这个寄存器其实就是往IENF里面写1,感觉有些多此一举)
- CIENF(W):Pin interrupt active level or falling edge interrupt clear register;不让引脚中断下降边沿敏感/高电平敏感(设置这个寄存器其实就是往IENF里面写0,感觉有些多此一举)
- RISE(R/W):Pin interrupt rising edge register;上升沿产生是置位
- FALL(R/W):Pin interrupt falling edge register;下降沿产生时置位
- IST(R/W):Pin interrupt status register;
(三)寄存器分析
ISEL:只有八个位PMODE,决定是电平敏感还是边沿敏感;
IENR、IENF等六个寄存器是使能上升下降边沿、高低电平中断的;
RISE、FALL、IST三个寄存器类似于标志位;
1、RISE
This register contains ones for pin interrupts selected in the PINTSELn registers (see table 216) on which a rising edge has been detected. Writing ones to this register clears rising edge detection. Ones in this register assert an interrupt request for pins that are enabled for rising-edge interrupts. All edges are detected for all pins selected by the PINTSELn registers, regardless of whether they are interrupt-enabled.
翻译:这个寄存器包含被PINTSELn寄存器(见表216)选中的引脚中断(这个PINTSELn寄存器是用来检测上升边沿)。往这个寄存器写一,清除上升沿检测标志。这个寄存器的位显示中断请求(中断请求来源于那些被使能上升沿中断的引脚)。所有在PINTSELn寄存器中被置位的引脚,他们的所有电平跳变边沿都会被检测到,不管他们是否使能了中断。
理解:也就是说只要是被PINTSELn寄存器选中的引脚,都会被检测电平跳变边沿,如果这个引脚使能了中断,发生上升沿跳变就会令这个寄存器相应位置位。(也即上升沿跳变标志位)
2、FALL
This register contains ones for pin interrupts selected in the PINTSELn registers (see Table 216) on which a falling edge has been detected. Writing ones to this register clears falling edge detection. Ones in this register assert an interrupt request for pins that are enabled for falling-edge interrupts. All edges are detected for all pins selected by the PINTSELn registers, regardless of whether they are interrupt-enabled.
翻译:这个寄存器包含被PINTSELn寄存器(见表216)选中的引脚中断(这个PINTSELn寄存器是用来检测下降边沿)。往这个寄存器写一,清除下降沿检测标志。这个寄存器的位显示中断请求(中断请求来源于那些被使能下降沿中断的引脚)。所有在PINTSELn寄存器中被置位的引脚,他们的所有电平跳变边沿都会被检测到,不管他们是否使能了中断。
理解:也就是说只要是被PINTSELn寄存器选中的引脚,都会被检测电平跳变边沿,如果这个引脚使能了中断,发生下降沿跳变就会令这个寄存器相应位置位。(也即下降沿跳变标志位)
3、IST
Reading this register returns ones for pin interrupts that are currently requesting an interrupt. For pins identified as edge-sensitive in the Interrupt Select register, writing ones to this register clears both rising- and falling-edge detection for the pin. For level-sensitive pins, writing ones inverts the corresponding bit in the Active level register, thus switching the active level on the pin.
翻译:读取这个寄存器会返回当前正在请求的那个引脚中断。对设置为边沿敏感(在中断选择寄存器the Interrupt Select register中设置)的引脚,往里面写1将会同时清除掉上升边沿、下降边沿的检测(标志位)。对于电平敏感的引脚,写1将会反转高电平寄存器(the Active level register)的对应位,从而转换引脚上的高电平。
理解:记录着正在发生的那个引脚中断。在边沿敏感的状态下,写一把上面两个寄存器RISE、FALL标志位清掉。(实际上不太确定是不是这样,毕竟个人英文水平有限,不知道有没有翻译错)
(四)分析用户手册配置引脚中断的流程
由上可得,确定了要中断的引脚后只需要做两步:
- 设置PINTSEL寄存器
- 在NVIC里面使能每个引脚中断
1、针对第一点:设置PINTSEL寄存器函数手册:
对应函数:
可以看到函数和PINTSEL寄存器一一对应。
数据手册第12章:
对应寄存器:
这个引脚中断寄存器里面保存的就是引脚信息,功能是把引脚和引脚中断之间的关系映射上!详细点说,引脚有两个组PIO0和PIO1,每个组里面有很多个引脚,比如PIO0有32个。但引脚中断只有8个,引脚中断和引脚之间是耦合的关系,想要配置可用的中断,必须把引脚和引脚中断只见的关系映射好,这8个寄存器就是做这个工作。
2、针对第二点:在NVIC里面使能每个引脚中断
在module里面:
(五)例程
- #include "board.h"
- /** @defgroup PERIPH_PININT_5411X Pin Interrupt example
- * @ingroup EXAMPLES_PERIPH_5411X
- * @include "periph_pinint\readme.txt"
- */
- /**
- * @}
- */
- /*****************************************************************************
- * Private types/enumerations/variables
- ****************************************************************************/
- #if defined(BOARD_NXP_LPCXPRESSO_54114)
- /* GPIO pin for PININT interrupt */
- #define GPIO_PININT_PORT 0 /* GPIO port number mapped to PININT */
- #define GPIO_PININT_PIN 24 /* GPIO pin number mapped to PININT */
- #define GPIO_PININT_INDEX PININTSELECT0 /* PININT index used for GPIO mapping */
- #define PININT_IRQ_HANDLER PIN_INT0_IRQHandler /* GPIO interrupt IRQ function name */
- #define PININT_NVIC_NAME PIN_INT0_IRQn /* GPIO interrupt NVIC interrupt name */
- #else
- #error "PININT not configured for this example"
- #endif /* defined (BOARD_NXP_LPCXPRESSO_54114) */
- /*****************************************************************************
- * Private types/enumerations/variables
- ****************************************************************************/
- /*****************************************************************************
- * Private functions
- ****************************************************************************/
- /*****************************************************************************
- * Public functions
- ****************************************************************************/
- /**
- * @brief Handle interrupt from GPIO pin or GPIO pin mapped to PININT
- * @return Nothing
- */
- void PININT_IRQ_HANDLER(void)
- {
- Chip_PININT_ClearIntStatus(LPC_PININT, PININTCH(GPIO_PININT_INDEX));
- Board_LED_Toggle(0);
- }
- /**
- * @brief Main program body
- * @return Does not return
- */
- int main(void)
- {
- int loop = 1; /* Used to fix the unreachable statement warning */
- /* Generic Initialization */
- SystemCoreClockUpdate();
- /* Board_Init calls Chip_GPIO_Init and enables GPIO clock if needed,
- Chip_GPIO_Init is not called again */
- Board_Init();
- Board_LED_Set(0, false);
- Chip_PININT_Init(LPC_PININT);
- /* Configure GPIO pin as input */
- Chip_GPIO_SetPinDIRInput(LPC_GPIO, GPIO_PININT_PORT, GPIO_PININT_PIN);
- /* Configure pin as GPIO */
- Chip_IOCON_PinMuxSet(LPC_IOCON, GPIO_PININT_PORT, GPIO_PININT_PIN, (IOCON_FUNC0 | IOCON_DIGITAL_EN | IOCON_GPIO_MODE));
- /* Configure pin interrupt selection for the GPIO pin in Input Mux Block */
- Chip_INMUX_PinIntSel(GPIO_PININT_INDEX, GPIO_PININT_PORT, GPIO_PININT_PIN);
- /* Configure channel interrupt as edge sensitive and falling edge interrupt */
- Chip_PININT_ClearIntStatus(LPC_PININT, PININTCH(GPIO_PININT_INDEX));
- Chip_PININT_SetPinModeEdge(LPC_PININT, PININTCH(GPIO_PININT_INDEX));
- Chip_PININT_EnableIntLow(LPC_PININT, PININTCH(GPIO_PININT_INDEX));
- /* Enable interrupt in the NVIC */
- NVIC_EnableIRQ(PININT_NVIC_NAME);
- /* Go to sleep mode - LED will toggle on each wakeup event */
- while (loop) {
- /* Sleep until next Pin Interrupt */
- __WFI();
- }
- return 0;
- }
复制代码 可以看到,例程其实跟数据手册说得也没有多大出入,其中,数据手册的两个步骤是没有考虑到设置第12章的那些寄存器。
(六)例程步骤分析
例程的配置过程分为四个部分:- 引脚初始化
- 设置PINTSEL寄存器
- 设置各种中断模式(即设置第12章那些寄存器)
- 在NVIC里面使能每个引脚中断
1、引脚初始化
- Chip_PININT_Init(LPC_PININT);
- /* Configure GPIO pin as input */
- Chip_GPIO_SetPinDIRInput(LPC_GPIO, GPIO_PININT_PORT, GPIO_PININT_PIN);
- /* Configure pin as GPIO */
- Chip_IOCON_PinMuxSet(LPC_IOCON, GPIO_PININT_PORT, GPIO_PININT_PIN, (IOCON_FUNC0 | IOCON_DIGITAL_EN | IOCON_GPIO_MODE));
复制代码
2、设置PINTSEL寄存器
- /* Configure pin interrupt selection for the GPIO pin in Input Mux Block */
- Chip_INMUX_PinIntSel(GPIO_PININT_INDEX, GPIO_PININT_PORT, GPIO_PININT_PIN);
复制代码
看看Chip_INMUX_PinIntSel这个函数,在inmux_5411x.h里面:
- /**
- * @brief GPIO Pin Interrupt Pin Select (sets PINTSEL register)
- * @param pintSel : GPIO PINTSEL interrupt, should be: 0 to 7
- * @param portNum : GPIO port number interrupt, should be: 0 to 1
- * @param pinNum : GPIO pin number Interrupt, should be: 0 to 31
- * @return Nothing
- */
- __STATIC_INLINE void Chip_INMUX_PinIntSel(uint8_t pintSel, uint8_t portNum, uint8_t pinNum)
- {
- LPC_INMUX->PINTSEL[pintSel] = (portNum * 32) + pinNum;
- }
复制代码
明显就是在操作PINTSEL寄存器,跟猜测的一模一样!也就是通过这一步,把引脚和引脚中断之间的关系映射上!详细点说,引脚有两个组PIO0和PIO1,每个组里面有很多个引脚,比如PIO0有32个。但引脚中断只有8个,引脚中断和引脚之间是耦合的关系,想要配置可用的中断,必须把引脚和引脚中断只见的关系映射好,这8个寄存器就是做这个工作。
3、设置各种中断模式(即设置第12章那些寄存器)
- /* Configure channel interrupt as edge sensitive and falling edge interrupt */
- Chip_PININT_ClearIntStatus(LPC_PININT, PININTCH(GPIO_PININT_INDEX));
- Chip_PININT_SetPinModeEdge(LPC_PININT, PININTCH(GPIO_PININT_INDEX));
- Chip_PININT_EnableIntLow(LPC_PININT, PININTCH(GPIO_PININT_INDEX));
复制代码
看看这几个函数:
Chip_PININT_ClearIntStatus(操作IST寄存器,把所有中断标志位清掉):
- /**
- * @brief Clear interrupt status in Pin interrupt block
- * @param pPININT : The base address of Pin interrupt block
- * @param pins : Pin interrupts to clear (ORed value of PININTCH*)
- * @return Nothing
- */
- __STATIC_INLINE void Chip_PININT_ClearIntStatus(LPC_PIN_INT_T *pPININT, uint32_t pins)
- {
- pPININT->IST = pins;
- }
复制代码
Chip_PININT_SetPinModeEdge(操作ISEL寄存器,设置边沿模式):
- /**
- * @brief Configure the pins as edge sensitive in Pin interrupt block
- * @param pPININT : The base address of Pin interrupt block
- * @param pins : Pins (ORed value of PININTCH*)
- * @return Nothing
- */
- __STATIC_INLINE void Chip_PININT_SetPinModeEdge(LPC_PIN_INT_T *pPININT, uint32_t pins)
- {
- pPININT->ISEL = (pPININT->ISEL & PININT_ISEL_PMODE_MASK) & ~pins;
- }
复制代码
Chip_PININT_EnableIntLow(操作SIENF寄存器,让引脚中断下降边沿敏感/高电平敏感,由于上面设置的是边沿模式,所以是下降边沿敏感):
- /**
- * @brief Enable falling edge/level active level PININT interrupts for pins
- * @param pPININT : The base address of Pin interrupt block
- * @param pins : Pins to enable (ORed value of PININTCH*)
- * @return Nothing
- */
- __STATIC_INLINE void Chip_PININT_EnableIntLow(LPC_PIN_INT_T *pPININT, uint32_t pins)
- {
- pPININT->SIENF = pins;
- }
复制代码
4、在NVIC里面使能每个引脚中断
- /* Enable interrupt in the NVIC */
- NVIC_EnableIRQ(PININT_NVIC_NAME);
复制代码
(七)再来仔细分析一下引脚初始化
1、初始化引脚第一步,初始化函数Chip_PININT_Init:
- /**
- * @brief Initialize Pin interrupt block
- * @param pPININT : The base address of Pin interrupt block
- * @return Nothing
- * @note This function should be used after the Chip_GPIO_Init() function.
- */
- __STATIC_INLINE void Chip_PININT_Init(LPC_PIN_INT_T *pPININT)
- {
- Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_PINT);
- Chip_SYSCON_PeriphReset(RESET_PINT);
- }
复制代码 使能时钟
2、设置GPIO为输入模式
Chip_GPIO_SetPinDIRInput:
- /**
- * @brief Set GPIO direction for a single GPIO pin to an input
- * @param pGPIO : The base of GPIO peripheral on the chip
- * @param port : GPIO port to set
- * @param pin : GPIO pin to set direction on as input
- * @return Nothing
- */
- __STATIC_INLINE void Chip_GPIO_SetPinDIRInput(LPC_GPIO_T *pGPIO, uint8_t port, uint8_t pin)
- {
- pGPIO->DIR[port] &= ~(1UL << pin);
- }
复制代码
3、设置引脚为GPIO模式
- /**
- * @brief Sets I/O Control pin mux
- * @param pIOCON : The base of IOCON peripheral on the chip
- * @param port : GPIO port to mux
- * @param pin : GPIO pin to mux
- * @param modefunc : OR'ed values or type IOCON_*
- * @return Nothing
- */
- __STATIC_INLINE void Chip_IOCON_PinMuxSet(LPC_IOCON_T *pIOCON, uint8_t port, uint8_t pin, uint32_t modefunc)
- {
- pIOCON->PIO[port][pin] = modefunc;
- }
复制代码 这里所操作的寄存器是用户手册第9章的I/O PIN configuration(IOCON):
PIO[port][pin]:
每个寄存器的位信息:
所以说对应的modefunc只需要通过或运算把需要置位的各个位的宏定义结合起来传进去就行,
像本例程的写法:
- (IOCON_FUNC0 | IOCON_DIGITAL_EN | IOCON_GPIO_MODE)
复制代码 这里分别是:
最后这个IOCON_GPIO_MODE直接看看不出来,转到定义:
- #define IOCON_GPIO_MODE (0x1 << 5) /*!< GPIO Mode */
复制代码
第五位置位,就是上拉模式。
|
评分
-
查看全部评分
|