Is there any way to force an array to be in Teensy 3.6 SRAM_U?

Status
Not open for further replies.

Bill Greiman

Well-known member
I have written a ring buffer class for buffering data during SD busy time. It works well if I use it for buffering full sectors. I have declared the buffer array like this. Size is a multiple of 512 bytes so everything is 32-bit aligned and sizes are a multiple of 32-bits.

Code:
uint8_t __attribute__ ((aligned (4))) m_buf[Size];

I also use it with Print as a base class and I have implemented write required by print with memcpy. It's really handy in a logger to print into the ring buffer. Even though memcpy is called in the class with type uint8_t arguments, the compiler optimizes it so a hard fault occurs when copying across the RAM_L/RAMU boundary in cases where the destination is not 32-bit aligned.

Is there an attribute that would cause the entire array to be in RAM_U?

Anyone have a custom memcpy for Teensy 3.6 that is efficient?
 
This seems to work. It is efficient except at the 0X20000000 boundary.
Code:
// Tensy3 memcpy
inline bool is_aligned(const void* ptr, uintptr_t alignment) {
    auto iptr = reinterpret_cast<uintptr_t>(ptr);
    return !(iptr % alignment);
}
void memcpyT3(void* dst, const void* src, size_t len) {
  const uint8_t* b = (const uint8_t*)0X20000000UL;
  uint8_t* d = (uint8_t*)dst;
  const uint8_t *s = (const uint8_t*)src;
  if (((d < b && (d + len) >= b) || (s < b && (s + len) >= b)) &&
    (!is_aligned(d, 4) || !is_aligned(s, 4) || len & 3)) {
    while (len--) {
      *d++ = *s++;
    }
  } else {
    memcpy(dst, src, len);
  }
}
 
Unfortunately the source buffer comes from the Print class and the destination buffer alignment depends on how many bytes have been written to the file.

I tested the above on a demo of a data logger that uses mods I am doing to the Teensy SDIO driver that include file.isBusy(). The logger can log adc value as text at over 25 ksps.

It's really simple so novice users can log a sensor at high rates without a sophisticated ISR approach. Here is the simplified code for the logger:

Code:
// 400 sector ring buffer for FsFile type.
RingBuf<FsFile, 400*512> rb;

  // Initialize the RingBuf - use a large pre-allocated exFAT file.
  rb.begin(&file); 
  
  // Used for controlling the log interval.
  uint32_t logTime = micros();
  while (!Serial.available()) {

    // Write data to SD if a sector is in the RingBuf.   
    if (rb.bytesUsed() >= 512 && !file.isBusy()) {
      // Writing full sectors assures no copy to SdFat internal cache buffer.
      // Write of first sector takes about 11 usec on Teensy 4.1, 5 usec each after the first.
      if (512 != rb.writeOut(512)) {
        // Handle SD write error here.
      }
    }
    // Time for next point - log at 25 kHz.
    logTime += 40;
    // Spare time before next point - negative if time overrun.
    int32_t spareMicros = logTime - micros();
    // Wait until time to log data.
    while (micros() < logTime) {}    
    
    // Read ADC0 this takes about 17 usec on Teensy 4.
    uint16_t adc = analogRead(0);
    // Print spareMicros into the RingBuf as test data.
    rb.print(spareMicros);
    rb.write(',');
    // Print adc into RingBuf.
    rb.println(adc);
    if (rb.getWriteError()) {
      // Handle error caused by too few free bytes in RingBuf.
    }
  }
 
The RingBuf class can be used in an ISR. I did a ping-pong ADC DMA test with Teensy 3.6 over-clocking the ADC and am able to log 6MB/sec.

Here is a link to that demo.

https://forum.pjrc.com/threads/65836-SdFat-DMA-over-clocked-3-Msps-ADC-logger?p=267092#post267092

TeensySqr.jpg
 
I have posted the mods to the Teensy SDIO driver that allow fast simple loggers and the ring buffer for use in SRAM_L/SRAM_U on Teensy 3.6.

Try the TeensyDmaAdcLogger and TeensySdioLogger examples.

Enable this line in TeensyDmaAdcLogger on a Teensy 3.6 to log an overclocked ADC at 6 MB/sec or 3 Msps.

Code:
// in loop()
//overclock(); // 3 Msps on Teensy 3.6 - requires high quality card.
 
Status
Not open for further replies.
Back
Top