STM32ADC带DMA,DMA不将数据写入内存位置



我正在尝试使用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部分。所以配置还是可以的

最新更新