How to grab a function value input it into DMA?

ajc225

Active member
I'm very new to DMA and I was wondering if there's a way to update a variable from a function and send it through DMA? I currently have 2 teensy 4.1 hookup to each other through Serial 6. I have code below that allows both teensys to send and receive messages from each other. However, I'm trying to update one of the values, that gets sent over, through a function. Currently, the value is not updating and I was wondering if someone could give advice and suggestions on how to do this?

Code:
#include "DMASensor.h"
#include "DMAnChannel.h"
#include "DMAUART.h"
#include "Avatar_pinmap.h"
#include "Avatar_params.h"

DMASensor currh, currh_link;
DMAUART uart_link;
DMAnChannel dma_curr_s, dma_curr_r, dma_link_s, dma_link_r;

//value to be updated
volatile uint16_t curr=3;

//receive array
volatile uint16_t rec_link[3];
//send array
uint16_t snd_link[3];

//counters
int i = 0;

void setup() {
  // put your setup code here, to run once:
  
  rec_link[0] = 255;
  snd_link[0] = 255;

  currh.init(16,POS_TC);

  currh.setAddr(snd_link+2);
  currh_link.setAddr(rec_link+2);
  
  uart_link.init(LINK_CH, link_uart);

  dma_curr_r.init(0, &curr, currh.getAddr(), 0, enc_receive_tcd);
  // Init DMA channels that handle sending/recieving position data over the device link bus
  dma_link_s.init(8, snd_link, &(uart_link.ctrl->DATA), 0, link_send_tcd);
  dma_link_r.init(9, &(uart_link.ctrl->DATA), rec_link, uart_link.dma_src_rx, link_receive_tcd);

  //update curr in send array every 10khz
  dma_curr_r.initPIT(2400);
  //send message after curr update
  dma_curr_r.linkCh(dma_link_s.ch);

  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  i=i+1;
  curr=currupdate();
  //snd_link[2] = curr;

  Serial.println(" ");
  Serial.print(rec_link[0]);
  Serial.print(" ");
  Serial.print(rec_link[1]);
  Serial.print(" ");
  Serial.print(rec_link[2]);
  Serial.println("");
  Serial.println(" ");
  Serial.print(snd_link[0]);
  Serial.print(" ");
  Serial.print(snd_link[1]);
  Serial.print(" ");
  Serial.print(snd_link[2]);
  Serial.println("");
}

uint16_t currupdate(){
  float f = 1.15+i*0.1;
  return (uint16_t) (f*1000);
}
 
Here's my updated code. For some reason I thought I needed to use the DMA functions to input an internal value into my array, but I actually can just update it in the main loop and it will send in the updated array. Also the link dma channel was not sending properly so I updated that. But it seems to be working I don't know if anyone can see some problems with doing it this way?

Code:
#include "DMASensor.h"
#include "DMAnChannel.h"
#include "DMAUART.h"
#include "Avatar_pinmap.h"
#include "Avatar_params.h"
#define sButton 33

#define LABELPRINT(label, value) Serial.print(label); Serial.print(": "); Serial.println(value);
#define PRINT(msg) Serial.println(msg);

DMASensor enc, currh, enc_link, currh_link;
DMAUART uart_enc, uart_link, uart_state;
DMAnChannel dma_enc_r, dma_enc_s, dma_curr_s, dma_curr_r, dma_link_s, dma_link_r, dma_state_s, dma_state_r;

uint32_t foo = 0xFFFFFFFF;

volatile uint16_t rec_link[3];
volatile uint16_t snd_link[3];
int i = 0;

void setup() {
  // put your setup code here, to run once:
  // Configure GPT1 for encoder reading timestamping
    CCM_CCGR1 |= CCM_CCGR1_GPT1_BUS(CCM_CCGR_ON); // Enable clock to GPT1 module
  GPT1_CR = 0; // Disable for configuration
  GPT1_PR = 2400-1; // Prescale 24 MHz clock by 3 => 8 MHz
  GPT1_CR = GPT_CR_EN /* Enable timer */
    | GPT_CR_CLKSRC(1) /* 24 MHz peripheral clock as clock source */
    | GPT_CR_FRR /* Free-Run, do not reset */;
  
  rec_link[0] = 255;
  snd_link[0] = 255;

  uart_link.init(LINK_CH, link_uart);

  dma_link_s.init(0, snd_link, &(uart_link.ctrl->DATA), uart_link.dma_src_tx, link_send_tcd);
  dma_link_r.init(9, &(uart_link.ctrl->DATA), rec_link, uart_link.dma_src_rx, link_receive_tcd);

  dma_link_s.initPIT(2400);

  pinMode(sButton, INPUT);
  Serial.begin(115200);
  Serial.print("init done");
  Serial.println("Press button to start");
  while (digitalRead(sButton) == HIGH){;}
  Serial.println("start");
}

void loop() {
  i=i+1;
  snd_link[2] = currupdate();
  if (i > 100){
    i=0;
  }

  Serial.print("record ");
  Serial.print(rec_link[0]);
  Serial.print(" ");
  Serial.print(rec_link[1]);
  Serial.print(" ");
  Serial.print(rec_link[2]);
  Serial.println("");

  Serial.print("send ");
  Serial.print(snd_link[0]);
  Serial.print(" ");
  Serial.print(snd_link[1]);
  Serial.print(" ");
  Serial.print(snd_link[2]);
  Serial.println("");
}

uint16_t currupdate(){
  float f = 1.15+i*0.1;
  return (uint16_t) (f*1000);
}
 
Last edited:
So I've been trying to send a bigger array of information now.
Code:
volatile uint16_t rec_link[5];
volatile uint16_t snd_link[5];
...
snd_link[4] = currupdate();

However, the teensys do not seem to like that. It keeps restarting randomly. I tried changing the .DLASTSGA of the link_recieve_tcd and .SLAST of the link_send_tcd from -6 to -10 because the array sized increased from 3 to 5. Am I allowed to do this? Am missing something I am supposed to change in the TCD or the LPUART? Or is there a capacity to how much I can send over one line and 3 was it?

Code:
TCD_t link_receive_tcd = {        // DMA configuration for recieving position data over the LINK channel
  .SADDR = 0, // Source address
  .SOFF = 0, // Adjustment to the source address made after every minor loop iteration
  .ATTR = (0b000000 << 11) | (0b000 << 8) | (0b000000 << 3) | (0b000), // SMOD | SSIZE | DMOD | DSIZE
  .NBYTES = 2,  // Set number of bytes to transfer per minor loop iteration
  .SLAST = 0, // Source address adjustment after major loop completion
  .DADDR = 0,  // Destination address
  .DOFF = 1,
  .CITER = (0b0 << 15) | 3, // CITER and BITER must be the same when the TCD memory is loaded by software. CITER will decrement with each minor loop
  .DLASTSGA = -10, //<-------- CHANGED THIS
  .CSR = (0b00 << 14) | (0b00000 << 8) | (0b0 << 5) | (0b0 << 4) | (0b0 << 3) | (0b0 << 2), // BWC | MAJORLINKCH | ESG | DREQ | INTHALF | INTMAJOR
  .BITER = (0b0 << 15) | 3 // Channel linking disabled | single service request (NO major looping)
};

TCD_t link_send_tcd = {        // DMA configuration for sending position data over the LINK channel
  .SADDR = 0, // Source address
  .SOFF = 1, // Adjustment to the source address made after every minor loop iteration
  .ATTR = (0b000000 << 11) | (0b000 << 8) | (0b000000 << 3) | (0b000), // SMOD | SSIZE | DMOD | DSIZE
  .NBYTES = 2,  // Set number of bytes to transfer per minor loop iteration
  .SLAST = -10, // <-------- CHANGED THIS
  .DADDR = 0,  // Destination address
  .DOFF = 0,
  .CITER = (0b0 << 15) | 3, // CITER and BITER must be the same when the TCD memory is loaded by software. CITER will decrement with each minor loop
  .DLASTSGA = 0,
  .CSR = (0b00 << 14) | (0b00000 << 8) | (0b0 << 5) | (0b0 << 4) | (0b0 << 3) | (0b0 << 2), // BWC | MAJORLINKCH | ESG | DREQ | INTHALF | INTMAJOR
  .BITER = (0b0 << 15) | 3 // Channel linking disabled | single service request (NO major looping)
};

LPUART_t link_uart = {
  
      .GLOBAL = 0x0, // LPUART1_GLOBAL
      .PINCFG = 0x0,
      .BAUD = 0xBA00001,
      .STAT = 0xC00000,
      .CTRL = 0x300000,
      .DATA = 0x1000,
      .MATCH = 0x0,
      .MODIR = 0x6,
      .FIFO = 0xC10099,
      .WATER = 0x20000 //& (0b11 << 10)
};
 
CITER and BITER are still set to 3, so it's looping 3 times and then moving the source/destination pointer back 5 words. Eventually it's probably overwriting something important.
 
Back
Top