Filip Jeretina
Filip Jeretina

Reputation: 71

STM32 ADC with DMA, DMA not writing data to memory location

I am trying to use the ADC on STM32f407G-DISC1 board to read joystick x and y position on pins PA2 and PA1 respectively and store the values to a memory location using the DMA.

I am configuring the ADC and DMA in the following way:

As soon as I Start conversion of regular channels on ADC1 (Set SWSTART in ADC_CR2)

STM32 reference manual

Why does my DMA not transfer any data to JOYSTICK_POS?

Here is the code I am using to configure the ADC and 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}

Upvotes: 0

Views: 1540

Answers (1)

Filip Jeretina
Filip Jeretina

Reputation: 71

Wrong .section

I have solved this issue by moving JOYSTICK_POS: .word 0 from .text section which is basically the code section and gets stored in ROM, to the .data section which is meant for storing data and gets stored in RAM. So the configuration was ok afterall.

Upvotes: 0

Related Questions