开始在我的博客更新nRF51822的学习笔记了,玩51822这么久一直都在蓝牙软件层玩,硬件这块特别陌生所以这次准备先把硬件过一遍。然后再更新软件篇的教程。很多笔记都存在为知笔记里,只先整理了一篇发出来后续有空会继续发。有错的地方大家请指出,欢迎讨论交流。
CPU: 32-bit ARM® Cortex™ M0 32-bit CPU
Memery:256/128 KB embedded flash、 16 KB RAM
System Peripherals:
一个32位定时器,两个16位定时器。(注:nRF51定时器的位数可以通过寄存器设置的,可变的)
16通道的CPU独立编程外设互联(PPI)
(翻译太渣,献原句:16 channel CPU independent Programmable Peripheral Interconnect (PPI))
128位AES ECB/CCM/AAR加密协处理器
RNG:随机数发生器
两个RTC时钟,RTC0,RTC1
温度传感器
GPIO:
31个GPIO引脚
支持多达4路PWM输出
Digital I/O:
SPI Master/Slave, 2-wire Master (I2C compatible), UART (CTS/RTS)
正交解码器(Quadrature decoder)
Analog I/O:
8/9/10 bit ADC - 8 configurable channels
Low power comparator
Power Management:
支持1.8V到3.6V宽电压
在芯片DC/DC转换
0.6 µA @ 3V OFF mode
1.2 µA @ 3V OFF mode + 1 region RAM retention
2.6 µA @ 3V ON mode, all blocks in idle mode
其他:
MPU
二、寄存器介绍
nRF51822的寄存器分为三类
* Task寄存器 :即该外设可以执行的task
* Event寄存器:即该外设带有的event
* 普通寄存器
Task寄存器和event寄存器在PPI的使用中是非常重要的,举个例子,在PPI中,设置EEP寄存器地址为某个外设A的Event寄存器地址,TEP寄存器设为另一个外设B的Task寄存器地址,那么当那个外设A的event发生时,可以直接触发执行外设B的task,而不经过CPU,这点在后面的PPI介绍中会有说明。
三、nRF51822的中断
1.nRF51822的中断源分别对应外设相应的event寄存器。
2.Nordic为了节省功耗把systick给去掉了,所以SysTick_Handler可以无视。
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
外部中断源也比常规的ARM芯片要少很多,SWI中断大多用在蓝牙协议栈中。
; External Interrupts
DCD POWER_CLOCK_IRQHandler OWER_CLOCK
DCD RADIO_IRQHandler ;RADIO
DCD UART0_IRQHandler ;UART0
DCD SPI0_TWI0_IRQHandler ;SPI0_TWI0
DCD SPI1_TWI1_IRQHandler ;SPI1_TWI1
DCD 0 ;Reserved
DCD GPIOTE_IRQHandler ;GPIOTE
DCD ADC_IRQHandler ;ADC
DCD TIMER0_IRQHandler ;TIMER0
DCD TIMER1_IRQHandler ;TIMER1
DCD TIMER2_IRQHandler ;TIMER2
DCD RTC0_IRQHandler ;RTC0
DCD TEMP_IRQHandler ;TEMP
DCD RNG_IRQHandler ;RNG
DCD ECB_IRQHandler ;ECB
DCD CCM_AAR_IRQHandler ;CCM_AAR
DCD WDT_IRQHandler ;WDT
DCD RTC1_IRQHandler ;RTC1
DCD QDEC_IRQHandler ;QDEC
DCD LPCOMP_IRQHandler ;LPCOMP
DCD SWI0_IRQHandler ;SWI0
DCD SWI1_IRQHandler ;SWI1
DCD SWI2_IRQHandler ;SWI2
DCD SWI3_IRQHandler ;SWI3
DCD SWI4_IRQHandler ;SWI4
DCD SWI5_IRQHandler ;SWI5
下面简单介绍一些外设,像定时器、GPIOTE、PPI等后面介绍。
四、NVMC
NVMC和其他ARM芯片一样,负责芯片Flash的擦写烧录,这里要说一下Nordic nRF51822 Flash结构。截图选自最新的softdevice 7.0.0.3alpha。新版的s110 softdevice将最底部的0×0~0×1000区域用作MBR,关于MBR和softdevice以及用户app之间的跳转过程,看我另一篇笔记 nRF51822-问答笔记【1】。也就是说Region0包含了Softdvice以及MBR,Region1包含了用户app和bootloader。
nRF51822芯片在flash操作上有个限制,为了保护R0区的softdevice不被破坏,它禁止了R1区的程序调用flash操作函数去读写R0区。也就是说,在softdevice6.0以及更早版本,我们是无法更新softdevice的,因为bootloader位于R1区。
当然你可以有个极端的办法,虽然我们无法单独擦除R0区代码,但nRF51822允许我们整个芯片擦除。所以,我们可以把程序拷贝到RAM中,在RAM中跑bootloader,对整个芯片的擦写,实现bootloader的升级。这样做的缺点很显示,一旦中途断电,整个芯片就瘫痪了。
为了实现softdevice的升级Nordic官方推出了新的softdevice 7.0,加入MBR使得bootloader可以调用MBR中的Flash操作函数实现softdevice升级。下面简单地介绍一下原理:
首先,上电后程序跳转到MBR中断向量入口,检测是否存在bootloader,存在则接着跳转到Bootload,在bootloader中,通过BLE方式或者串口方式收到新的softdevice firmware放在用户的app区,校验完毕,开始调用MBR中的flash擦写函数,覆盖旧版本的softdevice。
四、UICR寄存器的说明
UICR: 用户信息配置寄存器(User Information Configuration Registers)
UICR->CLENR0寄存器:很重要 CLENR0存放了Region0的大小,对于softdevice6.0需要设置为0×14000,对于softdevice 7.0要设置为0×15000。换句话说这个寄存器存放了用户APP的起始地址。(Region0存放softdevice,Region1存放APP、Bootloader)
UICR->RBCONF: read back protection,回读保护。保护的是region0的。
还有两个XTALFREQ寄存器和FWID寄存器不常用,见手册。
五、FICR寄存器
手册里面写的很详细,常用的寄存器有:
CODEPAGESIZE:softdevice将Region1的Flash分成一个个page,每个page的字节数存放在此。
CODESIZE:Flash被分成的总的page数
FICR寄存器组的东西很丰富,建议去看看手册,我用到的不多,其他的以后用到了再更新。
六、GPIO tasks and events (GPIOTE)
1.GPIOTE模块也是设计成减少了CPU占用的Task Event模式,使得事件可以不经过CPU就能得到响应。
Event引脚的触发源有:上升沿,下降沿等任何改变
Task引脚的操作方式有:置位,清0,反转
Event和task之间可以靠PPI连接在一起(见nRF51822学习笔记–硬件外设篇【3】PPI的描述)
2.一旦把某个引脚分配给Task(OUT[n])或Event(IN[n]),那么该引脚就只能被GPIOTE模块写操作,正常的GPIO写入时无效的。
3.当GPIOTE通道被配置用于操作一个任务引脚n,那么该引脚n的初值需要在CONFIG[n]寄存器的OUTINIT区域中设定。
4.GPIOE的事件触发源可以不仅仅只是某个引脚,还可以是某个port(nRF51把32个引脚分为4个port),同属一个port的任意一个引脚只要被检测到上升沿发生都会触发Port Event。
5.GPIOTE中断的使用。
/**
* @brief Function for configuring: pin 0 for input, pin 8 for output,
* and configures GPIOTE to give an interrupt on pin change.
*/
static void gpio_init(void)
{
nrf_gpio_cfg_input(BUTTON_0, BUTTON_PULL);
nrf_gpio_cfg_output(LED_0);nrf_gpio_pin_write(LED_0, BUTTON_0);// Enable interrupt:
NVIC_EnableIRQ(GPIOTE_IRQn);
//配置工作模式为event
//选择一个引脚作为event来源
//配置该event的触发源为翻转
NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos)
| (0 << GPIOTE_CONFIG_PSEL_Pos)
| (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
//开启4路GPIOTE通道中的IN0通道的中断
NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos;
}/** @brief Function for handling the GPIOTE interrupt which is triggered on pin 0 change.
*/
void GPIOTE_IRQHandler(void)
{
// Event causing the interrupt must be cleared.
if ((NRF_GPIOTE->EVENTS_IN[0] == 1) && //判断中断是否来自GPIOTE通道0
(NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN0_Msk))
{
NRF_GPIOTE->EVENTS_IN[0] = 0;
}
nrf_gpio_pin_toggle(LED_0);
}/**
* @brief Function for application main entry.
*/
int main(void)
{
gpio_init();
while (true)
{
// Do nothing.
}
}
6.GPIOTE配合PPI的使用,见PPI部分
Email: GavinYouSpace@gmail.com Created: 14-03-20 Updated: 14-03-20
一、介绍一下nRF51822片上资源CPU: 32-bit ARM® Cortex™ M0 32-bit CPU
Memery:256/128 KB embedded flash、 16 KB RAM
System Peripherals:
一个32位定时器,两个16位定时器。(注:nRF51定时器的位数可以通过寄存器设置的,可变的)
16通道的CPU独立编程外设互联(PPI)
(翻译太渣,献原句:16 channel CPU independent Programmable Peripheral Interconnect (PPI))
128位AES ECB/CCM/AAR加密协处理器
RNG:随机数发生器
两个RTC时钟,RTC0,RTC1
温度传感器
GPIO:
31个GPIO引脚
支持多达4路PWM输出
Digital I/O:
SPI Master/Slave, 2-wire Master (I2C compatible), UART (CTS/RTS)
正交解码器(Quadrature decoder)
Analog I/O:
8/9/10 bit ADC - 8 configurable channels
Low power comparator
Power Management:
支持1.8V到3.6V宽电压
在芯片DC/DC转换
0.6 µA @ 3V OFF mode
1.2 µA @ 3V OFF mode + 1 region RAM retention
2.6 µA @ 3V ON mode, all blocks in idle mode
其他:
MPU
二、寄存器介绍
nRF51822的寄存器分为三类
* Task寄存器 :即该外设可以执行的task
* Event寄存器:即该外设带有的event
* 普通寄存器
Task寄存器和event寄存器在PPI的使用中是非常重要的,举个例子,在PPI中,设置EEP寄存器地址为某个外设A的Event寄存器地址,TEP寄存器设为另一个外设B的Task寄存器地址,那么当那个外设A的event发生时,可以直接触发执行外设B的task,而不经过CPU,这点在后面的PPI介绍中会有说明。
三、nRF51822的中断
1.nRF51822的中断源分别对应外设相应的event寄存器。
2.Nordic为了节省功耗把systick给去掉了,所以SysTick_Handler可以无视。
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
外部中断源也比常规的ARM芯片要少很多,SWI中断大多用在蓝牙协议栈中。
; External Interrupts
DCD POWER_CLOCK_IRQHandler OWER_CLOCK
DCD RADIO_IRQHandler ;RADIO
DCD UART0_IRQHandler ;UART0
DCD SPI0_TWI0_IRQHandler ;SPI0_TWI0
DCD SPI1_TWI1_IRQHandler ;SPI1_TWI1
DCD 0 ;Reserved
DCD GPIOTE_IRQHandler ;GPIOTE
DCD ADC_IRQHandler ;ADC
DCD TIMER0_IRQHandler ;TIMER0
DCD TIMER1_IRQHandler ;TIMER1
DCD TIMER2_IRQHandler ;TIMER2
DCD RTC0_IRQHandler ;RTC0
DCD TEMP_IRQHandler ;TEMP
DCD RNG_IRQHandler ;RNG
DCD ECB_IRQHandler ;ECB
DCD CCM_AAR_IRQHandler ;CCM_AAR
DCD WDT_IRQHandler ;WDT
DCD RTC1_IRQHandler ;RTC1
DCD QDEC_IRQHandler ;QDEC
DCD LPCOMP_IRQHandler ;LPCOMP
DCD SWI0_IRQHandler ;SWI0
DCD SWI1_IRQHandler ;SWI1
DCD SWI2_IRQHandler ;SWI2
DCD SWI3_IRQHandler ;SWI3
DCD SWI4_IRQHandler ;SWI4
DCD SWI5_IRQHandler ;SWI5
下面简单介绍一些外设,像定时器、GPIOTE、PPI等后面介绍。
四、NVMC
NVMC和其他ARM芯片一样,负责芯片Flash的擦写烧录,这里要说一下Nordic nRF51822 Flash结构。截图选自最新的softdevice 7.0.0.3alpha。新版的s110 softdevice将最底部的0×0~0×1000区域用作MBR,关于MBR和softdevice以及用户app之间的跳转过程,看我另一篇笔记 nRF51822-问答笔记【1】。也就是说Region0包含了Softdvice以及MBR,Region1包含了用户app和bootloader。
nRF51822芯片在flash操作上有个限制,为了保护R0区的softdevice不被破坏,它禁止了R1区的程序调用flash操作函数去读写R0区。也就是说,在softdevice6.0以及更早版本,我们是无法更新softdevice的,因为bootloader位于R1区。
当然你可以有个极端的办法,虽然我们无法单独擦除R0区代码,但nRF51822允许我们整个芯片擦除。所以,我们可以把程序拷贝到RAM中,在RAM中跑bootloader,对整个芯片的擦写,实现bootloader的升级。这样做的缺点很显示,一旦中途断电,整个芯片就瘫痪了。
为了实现softdevice的升级Nordic官方推出了新的softdevice 7.0,加入MBR使得bootloader可以调用MBR中的Flash操作函数实现softdevice升级。下面简单地介绍一下原理:
首先,上电后程序跳转到MBR中断向量入口,检测是否存在bootloader,存在则接着跳转到Bootload,在bootloader中,通过BLE方式或者串口方式收到新的softdevice firmware放在用户的app区,校验完毕,开始调用MBR中的flash擦写函数,覆盖旧版本的softdevice。
四、UICR寄存器的说明
UICR: 用户信息配置寄存器(User Information Configuration Registers)
UICR->CLENR0寄存器:很重要 CLENR0存放了Region0的大小,对于softdevice6.0需要设置为0×14000,对于softdevice 7.0要设置为0×15000。换句话说这个寄存器存放了用户APP的起始地址。(Region0存放softdevice,Region1存放APP、Bootloader)
UICR->RBCONF: read back protection,回读保护。保护的是region0的。
还有两个XTALFREQ寄存器和FWID寄存器不常用,见手册。
五、FICR寄存器
手册里面写的很详细,常用的寄存器有:
CODEPAGESIZE:softdevice将Region1的Flash分成一个个page,每个page的字节数存放在此。
CODESIZE:Flash被分成的总的page数
FICR寄存器组的东西很丰富,建议去看看手册,我用到的不多,其他的以后用到了再更新。
六、GPIO tasks and events (GPIOTE)
1.GPIOTE模块也是设计成减少了CPU占用的Task Event模式,使得事件可以不经过CPU就能得到响应。
Event引脚的触发源有:上升沿,下降沿等任何改变
Task引脚的操作方式有:置位,清0,反转
Event和task之间可以靠PPI连接在一起(见nRF51822学习笔记–硬件外设篇【3】PPI的描述)
2.一旦把某个引脚分配给Task(OUT[n])或Event(IN[n]),那么该引脚就只能被GPIOTE模块写操作,正常的GPIO写入时无效的。
3.当GPIOTE通道被配置用于操作一个任务引脚n,那么该引脚n的初值需要在CONFIG[n]寄存器的OUTINIT区域中设定。
4.GPIOE的事件触发源可以不仅仅只是某个引脚,还可以是某个port(nRF51把32个引脚分为4个port),同属一个port的任意一个引脚只要被检测到上升沿发生都会触发Port Event。
5.GPIOTE中断的使用。
/**
* @brief Function for configuring: pin 0 for input, pin 8 for output,
* and configures GPIOTE to give an interrupt on pin change.
*/
static void gpio_init(void)
{
nrf_gpio_cfg_input(BUTTON_0, BUTTON_PULL);
nrf_gpio_cfg_output(LED_0);nrf_gpio_pin_write(LED_0, BUTTON_0);// Enable interrupt:
NVIC_EnableIRQ(GPIOTE_IRQn);
//配置工作模式为event
//选择一个引脚作为event来源
//配置该event的触发源为翻转
NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos)
| (0 << GPIOTE_CONFIG_PSEL_Pos)
| (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
//开启4路GPIOTE通道中的IN0通道的中断
NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos;
}/** @brief Function for handling the GPIOTE interrupt which is triggered on pin 0 change.
*/
void GPIOTE_IRQHandler(void)
{
// Event causing the interrupt must be cleared.
if ((NRF_GPIOTE->EVENTS_IN[0] == 1) && //判断中断是否来自GPIOTE通道0
(NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN0_Msk))
{
NRF_GPIOTE->EVENTS_IN[0] = 0;
}
nrf_gpio_pin_toggle(LED_0);
}/**
* @brief Function for application main entry.
*/
int main(void)
{
gpio_init();
while (true)
{
// Do nothing.
}
}
6.GPIOTE配合PPI的使用,见PPI部分