一旦我
我正在尝试使用STM32f407G-DISC1板上的ADC分别读取引脚PA2和PA1上的操纵杆x和y位置,并使用DMA将值存储到内存位置。
我以以下方式配置ADC和DMA:
- 启用ADC1时钟(在APB2ENR中设置ADC1EN(
- 重置所有ADC1寄存器
- 将ADC clk预分频器设置为除以6(在ADC_CR中将ADCPRE设置为0b10(
- 启用扫描模式(在ADC_CR1中设置scan(
- 设置CONT位,连续转换(在ADC_CR2中设置CONT(
- 启用每次转换后设置EOC标志(在ADC_CR2中设置EOCS(
- 启用DMA和DDS(在ADC_CR2中设置DMA和DDS(
- 将2个转换设置为常规通道序列长度(在ADC_SQR1中将L设置为0b1(
- 选择转换顺序为->PA1、PA2。(ADC_SQR3寄存器(
- 启用ADC1(ADC_CR2中的ADON位(
- 等待10ms,等待ADC稳定
- 启用DMA2时钟(设置AHB1ENR中的位22(
- 重置DMA_S0CR
- 等待DMA_S0CR中的EN位复位
- 重置DMA_LISR和DMA_HISR寄存器
- 选择通道0流0(DMA_S0CR中的CHSEL位(
- 选择存储器外围设备的方向(DMA_S0CR中的DIR位(
- 将外围数据大小和内存数据大小设置为半字,因为ADC分辨率设置为12位。(PSIZE,DMA_S0CR中的MSIZE(
- 将优先级设置为非常高(DMA_S0CR中的PL位(
- 启用循环模式(DMA_S0CR中的CIRC位(
- 启用内存增量模式(DMA_S0CR中的MINC位(
- 将2设置为要传输的数据项数(DMA_S0NDTR寄存器(
- 在DMA_S0PAR寄存器中设置stream0外围设备地址。我将此地址设置为
ADC1_BASE + ADC_DR
;所以ADC1的数据寄存器 - 将DMA_S0MAR中的stream0内存地址设置为
JOYSTICK_POS
的地址 - 启用流0(DMA_S0CR中的EN位(
- 重置ADC1状态寄存器(ADC_SR(
- 开始ADC1上常规通道的转换(在ADC_CR2中设置SWSTART(
一旦我Start conversion of regular channels on ADC1 (Set SWSTART in ADC_CR2)
- TCIF0和HTIF0标志在DMA2 LISR中设置
- 这些是传输完成和半传输标志,我不知道这些是否能阻止未来的数据传输。这些永远都不清楚
- 当我查看流0的NDTR寄存器时,每当ADC2 SR中的EOC标志被设置时,该值实际上都会递减,而且NDTR值在达到0之前会被设置回2,这是预期的行为,我想这意味着DMA的行为就像它在传输数据一样,然而,当我将数据从JOYSTICK_POS加载到r6中并查看调试器中的值时,它总是0,这意味着实际上没有任何内容被写入内存(或者至少没有在正确的位置?(
- 我还应该提到的是,ADC实际上正在将看起来正确的数据(根据物理操纵杆位置(转换并输入到DR寄存器中,数据由DMA读取,因为否则会设置OVR(超限(标志
STM32参考手册
为什么我的DMA没有将任何数据传输到JOYSTICK_POS
这是我用来配置ADC和DMA的代码
@RCC
.equ RCC_BASE, 0x40023800
.equ RCC_AHB1ENR, 0x30
.equ RCC_APB2ENR, 0x44
@ GPIOA
.equ GPIOA_BASE, 0x40020000
.equ GPIO_ODR, 0x14
.equ GPIO_BSRR, 0x18
.equ GPIO_AFRL, 0x20
.equ GPIO_AFRH, 0x24
@ ADC
.equ ADC1_BASE, 0x40012000
.equ ADC2_BASE, 0x40012100
.equ ADC3_BASE, 0x40012200
.equ ADC_SR, 0x0
.equ ADC_CR1, 0x4
.equ ADC_CR2, 0x8
.equ ADC_DR, 0x4c
.equ ADC_HTR, 0x24
.equ ADC_LTR, 0x28
.equ ADC_SQR1, 0x2c
.equ ADC_SQR2, 0x30
.equ ADC_SQR3, 0x34
.equ ADC_SMPR1, 0x0C
.equ ADC_SMPR2, 0x10
.equ ADC_CCR, 0x04
@ DMA
.equ DMA1_BASE, 0x40026000
.equ DMA2_BASE, 0x40026400
.equ DMA_LISR, 0x0
.equ DMA_HISR, 0x4
.equ DMA_S0CR, 0x10 + 0x18 * 0
.equ DMA_S3CR, 0x10 + 0x18 * 3
.equ DMA_S0_NDTR, 0x14 + 0x18 * 0
.equ DMA_S0PAR, 0x18 + 0x18 * 0
.equ DMA_S0M0AR, 0x1c + 0x18 * 0
.equ DMA_S0M1AR, 0x20 + 0x18 * 0
// SysTick Timer definitions
.equ SCS, 0xe000e000
.equ SCS_SYST_CSR, 0x10 // Control/Status register
.equ SCS_SYST_RVR, 0x14 // Value to countdown from
.equ SCS_SYST_CVR, 0x18 // Current value
.equ SYSTICK_RELOAD_1MS, 15999 //1 msec at 16MHz ... 16 000 000 / 500 - 1
.section .text
JOYSTICK_POS: .word 0 @ This is where I want to store the 2 position values
_start:
bl init_io
bl init_tc
bl init_adc1
bl enable_adc1
bl init_dma2
bl dma2_joystick_config
bl start_adc1
main:
@ Load the word at JOYSTICK_POS into r6. This will stay 0 for ever
ldr r6, JOYSTICK_POS
b main
dma2_joystick_config:
push { r5, r6, lr }
ldr r5, =DMA2_BASE
@ N of data items to transfer: 2
mov r6, #2
str r6, [r5, #DMA_S0_NDTR]
ldr r5, =DMA2_BASE
ldr r6, =ADC1_BASE + ADC_DR
str r6, [r5, #DMA_S0PAR]
adr r6, JOYSTICK_POS
str r6, [r5, #DMA_S0M0AR]
@ Enable stream
ldr r6, [r5, #DMA_S0CR]
orr r6, #1
str r6, [r5, #DMA_S0CR]
pop { r5, r6, pc }
init_dma2:
push { r5, r6, lr }
@ Enable DMA2 clock
ldr r5, =RCC_BASE
ldr r6, [r5, #RCC_AHB1ENR]
orr r6, #(1<<22)
str r6, [r5, #RCC_AHB1ENR]
ldr r5, =DMA2_BASE
mov r6, #0
str r6, [r5, #DMA_S0CR]
wait_dma2_reset:
ldr r6, [r5, #DMA_S0CR]
tst r6, #1
bne wait_dma2_reset
mov r6, #0
str r6, [r5, #DMA_LISR]
str r6, [r5, #DMA_HISR]
@ Channel 0, Stream 0
@ CHSEL: 0, DIR: Peripheral to memmory,
mov r6, #0
@ PSIZE, MSIZE hword
orr r6, #(0b01<<11)
orr r6, #(0b01<<13)
@ Priority very high
orr r6, #(0b11 << 16)
@ CIRC MODE ENABLE
orr r6, #(1<<8)
@ TCIE = 1
@ orr r6, #(1<<4)
@ MEMORY INC
orr r6, #(1<<10)
str r6, [r5, #DMA_S0CR]
pop { r5, r6, pc }
start_adc1:
push { r5, r6, lr }
ldr r5, =ADC1_BASE
mov r6, #0
str r6, [r5, #ADC_SR]
@ START
ldr r6, [r5, #ADC_CR2]
orr r6, #(1<<30)
str r6, [r5, #ADC_CR2]
pop { r5, r6, pc }
enable_adc1:
push { r5, r6, lr }
ldr r5, =ADC1_BASE
ldr r6, [r5, #ADC_CR2]
orr r6, #1
str r6, [r5, #ADC_CR2]
@ Wait (10ms) for ADC to stabilize
mov r0, #10
bl delay
pop { r5, r6, pc }
init_adc1:
push { r5, r6, lr }
@ Enable ADC1 clock
ldr r5, =RCC_BASE
ldr r6, [r5, #RCC_APB2ENR]
orr r6, #(1<<8)
str r6, [r5, #RCC_APB2ENR]
ldr r5, =ADC1_BASE
@ Reset adc registers
mov r6, #0
str r6, [r5, #ADC_CR2]
str r6, [r5, #ADC_CR1]
str r6, [r5, #ADC_SMPR1]
str r6, [r5, #ADC_SMPR2]
str r6, [r5, #ADC_SQR1]
str r6, [r5, #ADC_SQR2]
str r6, [r5, #ADC_SQR3]
str r6, [r5, #ADC_CCR]
@ CLK prescaler
orr r6, #(2<<16)
str r6, [r5, #ADC_CCR]
@ CR1 settings
@ SCAN MODE
orr r6, #(1<<8)
str r6, [r5, #ADC_CR1]
@CR2 settings
@ set CONT mode
mov r6, #0b10
@ EOC after each conversion
orr r6, #(1<<10)
@ Enable DMA, DDS
orr r6, #(0b11<<8)
str r6, [r5, #ADC_CR2]
@ Two conversions
mov r6, #(1<<20)
str r6, [r5, #ADC_SQR1]
@ Select order, PA1, PA2
mov r6, #1
orr r6, #(2 << 5)
str r6, [r5, #ADC_SQR3]
@ SAMPLE TIME
@ mov r6, #9
@ str r6, [r5, #ADC_SMPR2]
pop { r5, r6, pc }
init_io:
push { r5, r6, lr }
@ Enable GPIOA clock
ldr r5, =RCC_BASE
ldr r6, [r5, #RCC_AHB1ENR]
orr r6, #1
str r6, [r5, #RCC_AHB1ENR]
@ GPIOA_MODER
ldr r5, =GPIOA_BASE
@ set pins 1,2 as analog
ldr r6, [r5]
orr r6, #(0b11 << 2)
orr r6, #(0b11 << 4)
str r6, [r5]
pop { r5, r6, pc }
@ This is just code for the timer, so it's more clear what "bl delay" does
@ This works
init_tc:
push {r5, r6, lr}
ldr r6, =SCS
ldr r5, =SYSTICK_RELOAD_1MS
str r5, [r6, #SCS_SYST_RVR]
ldr r5, =0
str r5, [r6, #SCS_SYST_CVR]
ldr r5, =5
str r5, [r6, #SCS_SYST_CSR]
pop {r5, r6, pc}
delay:
push {r5, r6, lr}
ldr r5, =SCS
LOOPTC: ldr r6, [r5, #SCS_SYST_CSR]
tst r6, #0x10000
beq LOOPTC
subs r0, r0, 1
bne LOOPTC
pop {r5, r6, pc}
错误的部分
我通过移动JOYSTICK_POS: .word 0
解决了这个问题从基本上是代码部分并存储在ROM中的.text部分,到用于存储数据并存储在RAM中的.data部分。所以配置还是可以的