Teensy 4.0 First Beta Test

Status
Not open for further replies.
You might want to take a look at my ili9341_t3n version which supports the DMA buffering mode as well. Although I have used mine more in a different way then you had done with your _dma version in that I did not typically run it in continuous update mode. As I wanted more control on when things update as to not have probable flashing or partial updates...

Also I have not looked at the _dma version for awhile, but at least back then, my version may have been more complete, like supporting all 4 directions, all of the primitives were updated to work either buffered or not buffered, clipping, offsets...

Depending on who gets there first, I will try converting as well...

But right now probably higher priority to finish some of the SerialX support. I have more features on my machine to test out... Also not sure yet if SPI has the DMA (Async transfer) support yet? If not, would be a nice thing to add in... (At one point I had a 16 bit version transfer buffer async, which I was playing with and at that time I was playing with version of display library that used it... So all of the DMA support was taken care of by the SPI library... But that was awhile ago, before we then converted to SPI to use event responder.

Yes I did not need the additional functionality and partly it slows down things. But I'll take a look at your version now and add missing parts.
If it was for me only, I'd remove all boundary checks, rotation and more :) But I see - it can be useful, and I'll add it.
 
does anyone have issues setting certain registers? im still on beta5 not home yet to try beta6 yet, the POR for the CAN MCR register defaults to 16MBs, on the 3.x series it was only possible to change it by clearing those bits and writing a new value, however thats not working on the T4 version as it stays at 0xF indefinately, ill play more when i get home
 
I2C setClock() hack

I hacked setClock() in hardware/teensy/avr/libraries/Wire/WireIMXRT.cpp to set I2C clocks to 100khz, 400khz, or 1MHz.
Code:
void TwoWire::setClock(uint32_t frequency)
{
// thd using 24mhz clock, timing params, pg 2363
    port->MCR = 0;   // disable
    port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(1);   // 24 mhz/2  = 12 mhz
    if (frequency < 400000) {
        // 100 khz
        port->MCCR0 = LPI2C_MCCR0_CLKHI(53) | LPI2C_MCCR0_CLKLO(63) |
                      LPI2C_MCCR0_DATAVD(27) | LPI2C_MCCR0_SETHOLD(53);

    } else if (frequency < 1000000) {
        // 400 khz
        port->MCCR0 = LPI2C_MCCR0_CLKHI(8) | LPI2C_MCCR0_CLKLO(15) |
                      LPI2C_MCCR0_DATAVD(4) | LPI2C_MCCR0_SETHOLD(8);
    } else {
        // 1 mhz
        port->MCCR0 = LPI2C_MCCR0_CLKHI(4) | LPI2C_MCCR0_CLKLO(5) |
                      LPI2C_MCCR0_DATAVD(2) | LPI2C_MCCR0_SETHOLD(4);
    }
    port->MCFGR3 = LPI2C_MCFGR3_PINLOW(3900);  // optional  
    port->MFCR = LPI2C_MFCR_RXWATER(1) | LPI2C_MFCR_TXWATER(1);
    port->MCR = LPI2C_MCR_MEN;   // enable
}
Tested with I2C scanner sketch with BMP085 and with a BMP085 app. Teensy 4 core sets LPI2C peripheral clock to 24 mhz, setClock() divides it down to 12 mhz. With I2C clock at 100khz, scope measures 95.2 khz; at 400khz, scope measures 362 khz, and at 1MHz, scope measures 926khz. The BMP085 breakout board has 10K pullups and 1 mhz I2C wouldn't work with 10K pullups. I added 2.2K pullups in parallel to get the 1MHz test to work. I got similar scope measurements on the EVKB board with NXP SDK.
 
does anyone have issues setting certain registers? im still on beta5 not home yet to try beta6 yet, the POR for the CAN MCR register defaults to 16MBs, on the 3.x series it was only possible to change it by clearing those bits and writing a new value, however thats not working on the T4 version as it stays at 0xF indefinately, ill play more when i get home

ref manual says "This field can only be written in Freeze Mode as it is blocked by hardware in other modes" for MCR MAXMB field
Are you in freeze mode?
 
yes always in freeze mode ive tried, more or less everything is same as previous ifct/flexcan_library in terms of registers except now its possible to have 64 mailboxes instead of 16, and for the t3.x series it wasnt in the ref manual to clear the bits before changing it, a poster on nxp forums had an issue on the K series which later found out the bits need to be cleared first then changed, same method wont work in T4 in freeze mode, i didnt try clearing the entire MCR register yet but the MAXMB bits wont budge at all with same method in freeze mode
 
yes always in freeze mode ive tried, more or less everything is same as previous ifct/flexcan_library in terms of registers except now its possible to have 64 mailboxes instead of 16, and for the t3.x series it wasnt in the ref manual to clear the bits before changing it, a poster on nxp forums had an issue on the K series which later found out the bits need to be cleared first then changed, same method wont work in T4 in freeze mode, i didnt try clearing the entire MCR register yet but the MAXMB bits wont budge at all with same method in freeze mode

I don't speak CAN, but the NXP SDK (devices/MIMXRT1052/drivers/fsl_flexcan.c) has lines like
base->MCR |= CAN_MCR_WRNEN_MASK | CAN_MCR_MAXMB(FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base) - 1);
mcrTemp = (mcrTemp & ~CAN_MCR_MAXMB_MASK) | CAN_MCR_MAXMB(config->maxMbNum - 1);
so the SDK seems to be able to manipulate the MAXMB field ...
 
yup actually all bits there are not modifyable/changing, freeze mode or not, maybe its an initialization issue of some sort, still new to the new stuff :)
 
Can relate to Tony's plight. Having similar but different issue with setting the panic temperature in TEMPSENSE2. The Low Temp gets sets in the lower 12bits of TEMPSENSE2 which it is doing correctly but the upper 16 bits (only 12 are used for the Panic temp) isn't getting set correctly. Tried about 100 different ways to get it work but no luck. Here is whats happening:
Code:
alarmMode 1, Temp Code Val: 1255
TEMPMON_TEMPSENSE2: 0                         (Initial val of TEMPSENSE2 REG)
PanicValue 100111001110000000000000000        (Panic Temp in Counts shift to the upper 16 bits of the register - this is correct)
TEMPMON_TEMPSENSE2: 11100111  000   0000000000000  (TEMPSENSE2 |= PanicValue) This is wrong.
	     s/b 10011100111  000   0000000000000.  Keeps loosing leading 3 bits.

The high and low temp values are being set correctly so getting a little frustrated with this now. But here is the Panic Temp code associated with the output.
Code:
            /* Set panic alarm temperature code value */
            Serial.print("TEMPMON_TEMPSENSE2: "); Serial.println(TEMPMON_TEMPSENSE2,BIN);
            Serial.print("PanicValue "); Serial.println(TMS02_PANIC_ALARM_VALUE(tempCodeVal), BIN);

[COLOR="#FF0000"]            TEMPMON_TEMPSENSE2 |= TMS02_PANIC_ALARM_VALUE(tempCodeVal);
            //TEMPMON_TEMPSENSE2 |= ((TEMPMON_TEMPSENSE2&0xFF) | 1255UL << 16);
[/COLOR]
            Serial.print("TEMPMON_TEMPSENSE2: "); Serial.println(TEMPMON_TEMPSENSE2, BIN);
            Serial.println();
Talking to Tony we even tried hardcoding the value but same thing occurred.

If anyone has any ideas let me know.
 
Noting this here as possibly it's a BIOS issue or USB issue
I have an ASUS ROG RAMPAGE IV EXTREME mainboard, when I rebooted the PC it stopped booting (going past the BOOT slpash screen). After about 10-15 seconds you would hear the POST beep followed by a blue bar running accross the top of the splash screen as the POST hard faults there. After cycling power and rebooting it a few times, same issue every time. I disconnected the T4 and attempted a reboot, and it booted to windows. I went into the BIOS and verified the SSD was first boot drive, and it is, so it wasn't a USB BOOT attempt, I then went into the USB area and under the POST Initialization it was set to "Partial", I changed it to "Full" and the board boots fine with the T4 connected
 
If anyone has any ideas let me know.

Take a close look at the reference manual and the imxrt.h file
manual says TEMPSENSE2 is at 400D_8290 (or 400D_8000h base + 290h offset), but .h file says
#define TEMPMON_TEMPSENSE2 (IMXRT_TEMPMON.offset100)
where IMXRT_TEMPMON is 0x400D8180. The math doesn't match 400d8180 + 100 != 400d8290

... and then ref manual also has SET and CLR addresses ?
 
TEMPMON NOW FULLY FUNCTIONAL-Finally
Take a close look at the reference manual and the imxrt.h file
manual says TEMPSENSE2 is at 400D_8290 (or 400D_8000h base + 290h offset), but .h file says
#define TEMPMON_TEMPSENSE2 (IMXRT_TEMPMON.offset100)
where IMXRT_TEMPMON is 0x400D8180. The math doesn't match 400d8180 + 100 != 400d8290
THATS IT!. Works now. Matter of fact TEMPSENSE registers are wrong. Here are the correct ones:

Code:
#define TEMPMON_TEMPSENSE2		(IMXRT_TEMPMON.offset110)
#define TEMPMON_TEMPSENSE2_SET		(IMXRT_TEMPMON.offset114)
#define TEMPMON_TEMPSENSE2_CLR		(IMXRT_TEMPMON.offset118)
#define TEMPMON_TEMPSENSE2_TOG		(IMXRT_TEMPMON.offset11C)
Whats that old saying - when you are too close to the details ..

Thanks for checking.
Mike

EDIT: Can't believe I missed that - even checked and still didn't catch it. Anyway, when panic alarm is tripped the chip will reset. On startup if you then check (PSU_MISC1 >> 27U) & 1U) restart bit for panic temp we can decide what to do. Turn chip off (that one is all yours Frank B). Updating GitHub now.

Thanks again manitou.
 
Last edited:
DMA problems

I stumbled over the following issue
based on post https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=194344&viewfull=1#post194344
I tried to generalize further and found that the program only works for DMA channel 0

Any attempt to use another channel (e.g. 1) generates nonsense
In particular, the DADDR used inside the DMA-isr to know where the DMA is actual writing to, is not correct (even outside the destination array!)

Below the modified code
when setting SW_MODE to 1, output seems good, when setting SW_MODE to 2 , output is bad
Something is missing in the use of DMA

Code:
// I2S input test with DMA
//
// some missing macros/definitions
#define CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(n) ((uint32_t)(((n) & 0x03)<<19)) 
#define CCM_ANALOG_PLL_AUDIO_BYPASS ((uint32_t)(1<<16)) 
#define CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC(n) ((uint32_t)(((n) & 0x03)<<14)) 
#define CCM_ANALOG_PLL_AUDIO_ENABLE ((uint32_t)(1<<13)) 
#define CCM_ANALOG_PLL_AUDIO_POWERDOWN ((uint32_t)(1<<12)) 
#define CCM_ANALOG_PLL_AUDIO_DIV_SELECT(n) ((uint32_t)((n) & ((1<<6)-1))) 

#define CCM_ANALOG_MISC2_DIV_MSB (1u<<23)
#define CCM_ANALOG_MISC2_DIV_LSB (1u<<15)

#define CCM_ANALOG_PLL_AUDIO_NUM_MASK (((1<<29)-1))
#define CCM_ANALOG_PLL_AUDIO_DENOM_MASK (((1<<29)-1))

#define CCM_CSCMR1_SAI1_CLK_SEL_MASK (CCM_CSCMR1_SAI1_CLK_SEL(0x03))
#define CCM_CS1CDR_SAI1_CLK_PRED_MASK (CCM_CS1CDR_SAI1_CLK_PRED(0x07))
#define CCM_CS1CDR_SAI1_CLK_PODF_MASK (CCM_CS1CDR_SAI1_CLK_PODF(0x3f))

#define CCM_CSCMR1_SAI2_CLK_SEL_MASK (CCM_CSCMR1_SAI2_CLK_SEL(0x03))
#define CCM_CS2CDR_SAI2_CLK_PRED_MASK (CCM_CS2CDR_SAI2_CLK_PRED(0x07))
#define CCM_CS2CDR_SAI2_CLK_PODF_MASK (CCM_CS2CDR_SAI2_CLK_PODF(0x3f))

#define CCM_CSCMR1_SAI3_CLK_SEL_MASK (CCM_CSCMR1_SAI3_CLK_SEL(0x03))
#define CCM_CS1CDR_SAI3_CLK_PRED_MASK (CCM_CS1CDR_SAI3_CLK_PRED(0x07))
#define CCM_CS1CDR_SAI3_CLK_PODF_MASK (CCM_CS1CDR_SAI3_CLK_PODF(0x3f))
//
//
void set_audioClock(int nfact = 27, int32_t mult=0, uint32_t div=1)
{ 
  CCM_ANALOG_PLL_AUDIO = 0;
  //CCM_ANALOG_PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_BYPASS;
  CCM_ANALOG_PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_ENABLE;
  CCM_ANALOG_PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2); // 0: 1/4; 1: 1/2; 0: 1/1
  CCM_ANALOG_PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_DIV_SELECT(nfact);    
  
  CCM_ANALOG_PLL_AUDIO_NUM   = mult &CCM_ANALOG_PLL_AUDIO_NUM_MASK;
  CCM_ANALOG_PLL_AUDIO_DENOM = div &CCM_ANALOG_PLL_AUDIO_DENOM_MASK;
  
  const int div_post_pll = 1; // other values: 2,4
  CCM_ANALOG_MISC2 &= ~(CCM_ANALOG_MISC2_DIV_MSB | CCM_ANALOG_MISC2_DIV_LSB);
  if(div_post_pll>1)
    CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_LSB;
  if(div_post_pll>3)
    CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB;
}
//
void sai1_setClock(int n1, int n2) 
{ 
  CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);
  IOMUXC_GPR_GPR1 |= (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0));

  // clear SAI1_CLK register locations
  CCM_CSCMR1 &= ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK);
  CCM_CS1CDR &= ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK);
  //
  CCM_CSCMR1 |= CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4,  
  CCM_CS1CDR |= CCM_CS1CDR_SAI1_CLK_PRED(n1-1); // &0x07
  CCM_CS1CDR |= CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f   
}
//
void sai1_configurePorts(int iconf=0)
{
  CORE_PIN23_CONFIG = 3;  //1:MCLK
  CORE_PIN21_CONFIG = 3;  //1:RX_BITCLK
  CORE_PIN20_CONFIG = 3;  //1:RX_FS
  CORE_PIN7_CONFIG  = 3;  //1:RX_DATA0
  CORE_PIN8_CONFIG  = 3;  //1:RX_DATA1 // not used
  CORE_PIN9_CONFIG  = 3;  //1:RX_DATA2 // not used
  CORE_PIN32_CONFIG = 3;  //1:RX_DATA3 // not used
}
//subset of missing definitions
#define I2S_RCR1_RFW(n)     ((uint32_t)n & 0x1f)    // Receive FIFO watermark
#define I2S_RCR2_DIV(n)     ((uint32_t)n & 0xff)    // Bit clock divide by (DIV+1)*2
#define I2S_RCR2_BCD      ((uint32_t)1<<24)   // Bit clock direction
#define I2S_RCR2_MSEL(n)    ((uint32_t)(n & 3)<<26)   // MCLK select, 0=bus clock, 1=I2S0_MCLK
#define I2S_RCR2_SYNC(n)    ((uint32_t)(n & 3)<<30)   // 0=async 1=sync with receiver
#define I2S_RCR3_RCE        ((uint32_t)0x10000)   // receive channel enable
#define I2S_RCR4_FSD      ((uint32_t)1)     // Frame Sync Direction
#define I2S_RCR4_FSE      ((uint32_t)8)     // Frame Sync Early
#define I2S_RCR4_MF     ((uint32_t)0x10)    // MSB First
#define I2S_RCR4_SYWD(n)    ((uint32_t)(n & 0x1f)<<8) // Sync Width
#define I2S_RCR4_FRSZ(n)    ((uint32_t)(n & 0x0f)<<16)  // Frame Size
#define I2S_RCR5_FBT(n)     ((uint32_t)(n & 0x1f)<<8) // First Bit Shifted
#define I2S_RCR5_W0W(n)     ((uint32_t)(n & 0x1f)<<16)  // Word 0 Width
#define I2S_RCR5_WNW(n)     ((uint32_t)(n & 0x1f)<<24)  // Word N Width

#define I2S_RCSR_RE     ((uint32_t)0x80000000)    // Receiver Enable
#define I2S_RCSR_FR     ((uint32_t)0x02000000)    // FIFO Reset
#define I2S_RCSR_FRDE     ((uint32_t)0x00000001)    // FIFO Request DMA Enable
#define I2S_RCSR_BCE      ((uint32_t)0x10000000)    // Bit Clock Enable

typedef struct
{
  uint32_t CSR;
  uint32_t CR1,CR2,CR3,CR4,CR5;
  uint32_t DR[8];
  uint32_t FR[8];
  uint32_t MR;
} I2S_PORT;

typedef struct
{
  uint32_t VERID;
  uint32_t PARAM;
  I2S_PORT TX;
  uint32_t unused[9];
  I2S_PORT RX;
} I2S_STRUCT;

I2S_STRUCT *I2S1 = ((I2S_STRUCT *)0x40384000);
I2S_STRUCT *I2S2 = ((I2S_STRUCT *)0x40388000);
I2S_STRUCT *I2S3 = ((I2S_STRUCT *)0x4038C000);
//
#define NBITS 32
#define NW 2  // number of words / channel
#define NCH 1 // number of channels // allowed 1,2,4
#define TDM 0 // use short conv-flag
/*
 * e.g. 
 * single stereo: NW = 2; NCH = 1;
 * dual stereo:   NW = 2; NCH = 2;
 * quad stereo:   NW = 2; NCH = 4;
 * 8-ch TDM:      NW = 8; NCH = 1;
 * 4*8 ch TDM:    NW = 8; NCH = 4;
 */

#define NDAT 128 // number of samples / (words * channel)
#define NBUF (2*NW*NCH*NDAT)

int32_t rx_buffer[NBUF] __attribute__( ( aligned ( 0x1000 ) ) );
int32_t rx_data1 = (uint32_t)&rx_buffer[0];
int32_t rx_data2 = (uint32_t)&rx_buffer[NBUF/2];

void sai_rxConfig(int ndiv, int nch)
{
  I2S1->RX.MR = 0;
  I2S1->RX.CR1 = I2S_RCR1_RFW(1); 
  I2S1->RX.CR2 = I2S_RCR2_SYNC(0);// | I2S_RCR2_BCP ; // sync=0; rx is async; 

  I2S1->RX.CR2 |= (I2S_RCR2_BCD | I2S_RCR2_DIV(ndiv-1) | I2S_RCR2_MSEL(1));
  I2S1->RX.CR3 = 0;
  for(int ii=0; ii<nch; ii++)
    I2S1->RX.CR3 |= I2S_RCR3_RCE<<ii; // mark rx channel

Serial.println(I2S1->RX.CR3,HEX);
  //
  #if (TDM==0)
    int ns = NBITS;
  #elif (TDM==1)
    int ns = 1;
  #endif
  I2S1->RX.CR4 = I2S_RCR4_FRSZ(NW-1) 
        | I2S_RCR4_SYWD(ns-1) 
        | I2S_RCR4_MF
        #if (TDM==1)
        | I2S_RCR4_FSE 
        #endif
        | I2S_RCR4_FSD;

  I2S1->RX.CR5 = I2S_RCR5_WNW(NBITS-1) | I2S_RCR5_W0W(NBITS-1) | I2S_RCR5_FBT(NBITS-1);
}

IMXRT_DMA_TCD_t     *dma       ((IMXRT_DMA_TCD_t *)0x400E9000);
uint32_t            *dma_cfg   ((uint32_t *)0x400EC000);
volatile uint32_t dma_ch=0;

/****************************************************************/
#define SW_MODE 2  // SW_MODE=1: works SW_MODE=2 does not work

void sai_rx_isr(void); // forward declaration

void sai_setupInput(void * buffer, int nch, int nloop)
{ 
  //
  CCM_CCGR5 |= CCM_CCGR5_DMA(CCM_CCGR_ON);
  DMA_CR = 0;
  DMA_CR = DMA_CR_GRP1PRI | DMA_CR_EMLM | DMA_CR_EDBG;
  
#if SW_MODE==1 // this works
  DMAMUX_CHCFG0 = 0;
  DMAMUX_CHCFG0 = (DMAMUX_SOURCE_SAI1_RX & 0x7F) | DMAMUX_CHCFG_ENBL;

  // clear DMA registers
  DMA_TCD0_CSR = 0;
  DMA_TCD0_ATTR = 0;
  //
  // major loop
  DMA_TCD0_BITER = nloop;
  DMA_TCD0_CITER = DMA_TCD0_BITER;
  //
  // minor loop
  DMA_TCD0_NBYTES = 4*nch;
  #if NCH>1
    DMA_TCD0_NBYTES |= DMA_TCD_NBYTES_SMLOE ;
    DMA_TCD0_NBYTES |= DMA_TCD_NBYTES_MLOFFYES_MLOFF(-4*nch);
  #endif
  //
  // Source 
  DMA_TCD0_SADDR = (void *)&I2S1_RDR0;
  DMA_TCD0_ATTR |= DMA_TCD_ATTR_SSIZE(2);
  #if NCH>1
    DMA_TCD0_SOFF = 4;
    DMA_TCD0_SLAST = -4*nch;
  #else
    DMA_TCD0_SOFF = 0;
    DMA_TCD0_SLAST = 0;
  #endif
  //
  // Destination 
  DMA_TCD0_DADDR = buffer;
  DMA_TCD0_ATTR |= DMA_TCD_ATTR_DSIZE(2);
  DMA_TCD0_DOFF = 4;
  DMA_TCD0_DLASTSGA = -4*nch*nloop;
//
  DMA_TCD0_CSR |= DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;

  attachInterruptVector(IRQ_DMA_CH0, sai_rx_isr);
  NVIC_ENABLE_IRQ(IRQ_DMA_CH0);
  NVIC_SET_PRIORITY(IRQ_DMA_CH0, 7*16); // 8 is normal priority
  //
  I2S1->RX.CSR |= I2S_RCSR_FRDE | I2S_RCSR_FR;
  I2S1->RX.CSR |= I2S_RCSR_RE | I2S_RCSR_BCE;

  DMA_SERQ = dma_ch = 0;
  DMA_TCD0_CSR |=  DMA_TCD_CSR_START;
  /*******************************************************************************/
  
#elif SW_MODE==2 //  // to be fixed

  DMAMUX_CHCFG1 = 0;
  DMAMUX_CHCFG1 = (DMAMUX_SOURCE_SAI1_RX & 0x7F) | DMAMUX_CHCFG_ENBL;
  
  DMA_CERQ = 1;
  DMA_CERR = 1;
  DMA_CEEI = 1;
  DMA_CINT = 1;

  // clear DMA registers
  DMA_TCD1_CSR = 0;
  DMA_TCD1_ATTR = 0;
  
  //
  // major loop
  DMA_TCD1_BITER = nloop;
  DMA_TCD1_CITER = DMA_TCD1_BITER;
  //
  // minor loop
  DMA_TCD1_NBYTES = 4*nch;
  #if NCH>1
    DMA_TCD1_NBYTES |= DMA_TCD_NBYTES_SMLOE ;
    DMA_TCD1_NBYTES |= DMA_TCD_NBYTES_MLOFFYES_MLOFF(-4*nch);
  #endif
  //
  // Source 
  DMA_TCD1_SADDR = (void *)&I2S1_RDR0;
  DMA_TCD1_ATTR |= DMA_TCD_ATTR_SSIZE(2);
  #if NCH>1
    DMA_TCD1_SOFF = 4;
    DMA_TCD1_SLAST = -4*nch;
  #else
    DMA_TCD1_SOFF = 0;
    DMA_TCD1_SLAST = 0;
  #endif
  //
  // Destination 
  DMA_TCD1_DADDR = buffer;
  DMA_TCD1_ATTR |= DMA_TCD_ATTR_DSIZE(2);
  DMA_TCD1_DOFF = 4;
  DMA_TCD1_DLASTSGA = -4*nch*nloop;
//
  DMA_TCD1_CSR |= DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;

  attachInterruptVector(IRQ_DMA_CH1, sai_rx_isr);
  NVIC_ENABLE_IRQ(IRQ_DMA_CH1);
  NVIC_SET_PRIORITY(IRQ_DMA_CH1, 7*16); // 8 is normal priority
  //
  I2S1->RX.CSR |= I2S_RCSR_FRDE | I2S_RCSR_FR;
  I2S1->RX.CSR |= I2S_RCSR_RE | I2S_RCSR_BCE;

  DMA_SERQ = dma_ch = 1;
  DMA_TCD1_CSR |=  DMA_TCD_CSR_START;
#endif
}

#define I2S_PIN 3
void sai_rxProcessing(void * taddr);  // forward declaration
int32_t i2sCount1=0;
int32_t i2sCount2=0;
uint32_t maxPtr=0;
uint32_t minPtr=0x40000000;

void sai_rx_isr(void)
{ uint32_t daddr, taddr;
  //
  DMA_CINT = dma_ch;
  //
  daddr = (uint32_t) (DMA_TCD0_DADDR);
  if(daddr>maxPtr) maxPtr=daddr;
  if(daddr<minPtr) minPtr=daddr;
  if (daddr < (uint32_t)rx_data2) 
  {
    // DMA is receiving to the first half of the buffer
    // need to process data from the second half
    taddr=(uint32_t) rx_data2;
    //
    i2sCount1++;
    digitalWrite(I2S_PIN, HIGH);
  } 
  else 
  {
    // DMA is receiving to the second half of the buffer
    // need to process data from the first half
    taddr=(uint32_t) rx_data1;
    //
    i2sCount2++;
    digitalWrite(I2S_PIN, LOW);
  }
  //up call
  sai_rxProcessing((void *) taddr);
}

uint32_t rxCount = 0;
uint32_t maxVal=0;
void sai_rxProcessing(void * taddr)
{
  uint32_t *data = (uint32_t *) taddr;
  // do something useful
  rxCount++;
//  for(int ii=0; ii<NCH*NDAT;ii++)
//  if(data[ii]>maxVal) maxVal=data[ii];  
}

void setup() {
  // put your setup code here, to run once:
  while(!Serial);
  Serial.println("T4_Test");

  sai1_configurePorts();

  int fs = 192000;
  int bit_clk = fs*(NW*NBITS);
  int nov = 4; // factor of oversampling MCKL/BCKL
  int fs_mclk = nov*bit_clk; // here 49.152 MHz 
  Serial.printf("bits / word :       %d\n",NBITS);
  Serial.printf("words / channel :   %d\n",NW);
  Serial.printf("number of channel : %d\n",NCH);
  #if (TDM==1)
    Serial.printf("Mode: TDM\n");
  #else
    Serial.printf("Mode: I2S\n");
  #endif
  Serial.printf("Frame rate :  %9d Hz\n",fs);
  Serial.printf("Bit Clock :   %9d Hz\n",bit_clk);
  Serial.printf("Master Clock: %9d Hz\n",fs_mclk);
  //
  int c0, c1, c2;
  int n1, n2;

  n1 = 4; // to ensure that input to last divisor (i.e. n2) is < 300 MHz
  n2 = 4; // to reduce clock further to become MCLK

  // the PLL runs between 27*24 and 54*24 MHz (before dividers)
  // e.g. 49.152 = 32.768*24 / (n1*n2)
  c0 = 32;  
  c1 = 768;
  c2 = 1000;
  // Note: c0+c1/c2 must be between 27 and 54
  //       here: 32.768*24 MHz = 786.4320 MHz

  set_audioClock(c0,c1,c2);
  sai1_setClock(n1,n2);

  int ndiv = nov/2;   // MCLK -> 2* BitClock
  sai_rxConfig(ndiv, NCH);
  sai_setupInput(rx_buffer, NCH, 2*NW*NDAT);

  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(I2S_PIN,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  Serial.printf("%d %d %d %d %x %x %x - %x %x - %x\n",rxCount,maxVal,
                  i2sCount1,i2sCount2, 
                  maxPtr, minPtr, (uint32_t)rx_data2,
                  (uint32_t)&rx_buffer[0], (uint32_t)&rx_buffer[NBUF], 
                  (uint32_t)dma[dma_ch].CSR);
  rxCount=0;
  maxVal=0;
  i2sCount1=0;
  i2sCount2=0;
  maxPtr=0;
  minPtr=0x40000000;
}
 
I2C setClock() hack
@manitou
Gave you fix an try with the MPU-9250 plus pressure sensor. At 400khz it picked up all three sensors:
Code:
I2C device found at address 0x0C  !
I2C device found at address 0x68  !
I2C device found at address 0x76  !
and the test sketch ran no problem.

At 1Mhz it picked up the pressure sensor and accel/gyro piece of the 9250 (not the mag). It was able to read and calibrate the gyro/accel but hung on the magnetometer - have to pull out the spec again but i thing its only rated at 400khz. But looks like the hack is working/fix is working.
 
I2C setClock() hack
@manitou
Gave you fix an try with the MPU-9250 plus pressure sensor. At 400khz it picked up all three sensors:
Code:
I2C device found at address 0x0C  !
I2C device found at address 0x68  !
I2C device found at address 0x76  !
and the test sketch ran no problem.

At 1Mhz it picked up the pressure sensor and accel/gyro piece of the 9250 (not the mag). It was able to read and calibrate the gyro/accel but hung on the magnetometer - have to pull out the spec again but i thing its only rated at 400khz. But looks like the hack is working/fix is working.

The magnetometer will not show up on an I2C scan unless you specifically set the MPU-9250 into bypass mode (register 55, bit 1).

Edit: mis-read post, looks like you have it in bypass mode to pick it up at 400 kHz. Surprised it works at the higher speeds - the max bus speed in the spec is 400 kHz.
 
Surprised it works at the higher speeds - the max bus speed in the spec is 400 kHz.
Just did a double check and yep, supposedly the max bus speed for the 6500 is 400khz.
 
Bug

Found a mysterious bug:

As soon i use a memset-like operation (a simple loop filling an array with 0, or a real memset) the Arduino-Builder makes nonsense:
Code:
C:\Arduino\arduino-builder -dump-prefs -logger=machine -hardware C:\Arduino\hardware -hardware C:\Users\Frank\AppData\Local\Arduino15\packages -hardware C:\Users\Frank\Documents\Arduino\hardware -tools C:\Arduino\tools-builder -tools C:\Arduino\hardware\tools\avr -tools C:\Users\Frank\AppData\Local\Arduino15\packages -built-in-libraries C:\Arduino\libraries -libraries C:\Users\Frank\Documents\Arduino\libraries -fqbn=teensy:avr:teensy4b:usb=serial,opt=o1std,keys=en-us -ide-version=10808 -build-path c:\temp\arduino_build_359487 -warnings=more -build-cache c:\temp\arduino_cache_387431 -verbose C:\Users\Frank\Documents\Arduino\T4_ILI9341\T4_ILI9341.ino
C:\Arduino\arduino-builder -compile -logger=machine -hardware C:\Arduino\hardware -hardware C:\Users\Frank\AppData\Local\Arduino15\packages -hardware C:\Users\Frank\Documents\Arduino\hardware -tools C:\Arduino\tools-builder -tools C:\Arduino\hardware\tools\avr -tools C:\Users\Frank\AppData\Local\Arduino15\packages -built-in-libraries C:\Arduino\libraries -libraries C:\Users\Frank\Documents\Arduino\libraries -fqbn=teensy:avr:teensy4b:usb=serial,opt=o1std,keys=en-us -ide-version=10808 -build-path c:\temp\arduino_build_359487 -warnings=more -build-cache c:\temp\arduino_cache_387431 -verbose C:\Users\Frank\Documents\Arduino\T4_ILI9341\T4_ILI9341.ino
Using board 'teensy4b' from platform in folder: C:\Arduino\hardware\teensy\avr
Using core 'teensy4' from platform in folder: C:\Arduino\hardware\teensy\avr
Detecting libraries used...
"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -fsingle-precision-constant -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "c:\\temp\\arduino_build_359487\\sketch\\T4_ILI9341.ino.cpp" -o nul
"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -fsingle-precision-constant -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "c:\\temp\\arduino_build_359487\\sketch\\ILI9341_t4.cpp" -o nul
"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -fsingle-precision-constant -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "-IC:\\Arduino\\hardware\\teensy\\avr\\libraries\\SPI" "c:\\temp\\arduino_build_359487\\sketch\\ILI9341_t4.cpp" -o nul
Using cached library dependencies for file: C:\Arduino\hardware\teensy\avr\libraries\SPI\SPI.cpp
Generating function prototypes...
"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -fsingle-precision-constant -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "-IC:\\Arduino\\hardware\\teensy\\avr\\libraries\\SPI" "c:\\temp\\arduino_build_359487\\sketch\\T4_ILI9341.ino.cpp" -o "c:\\temp\\arduino_build_359487\\preproc\\ctags_target_for_gcc_minus_e.cpp"
"C:\\Arduino\\tools-builder\\ctags\\5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "c:\\temp\\arduino_build_359487\\preproc\\ctags_target_for_gcc_minus_e.cpp"
Sketch wird kompiliert...
"C:\\Arduino\\hardware\\teensy/../tools/precompile_helper" "C:\\Arduino\\hardware\\teensy\\avr/cores/teensy4" "c:\\temp\\arduino_build_359487" "C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -x c++-header -O1 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -fsingle-precision-constant -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Arduino\\hardware\\teensy\\avr/cores/teensy4" "c:\\temp\\arduino_build_359487/pch/Arduino.h" -o "c:\\temp\\arduino_build_359487/pch/Arduino.h.gch"
Using previously compiled file: c:\temp\arduino_build_359487\pch\Arduino.h.gch

"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -c -O1 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -fsingle-precision-constant -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-Ic:\\temp\\arduino_build_359487/pch" "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "-IC:\\Arduino\\hardware\\teensy\\avr\\libraries\\SPI" "c:\\temp\\arduino_build_359487\\sketch\\T4_ILI9341.ino.cpp" -o "c:\\temp\\arduino_build_359487\\sketch\\T4_ILI9341.ino.cpp.o"
"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -c -O1 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -fsingle-precision-constant -D__IMXRT1052__ -DTEENSYDUINO=146 -DARDUINO=10808 -DF_CPU=396000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-Ic:\\temp\\arduino_build_359487/pch" "-IC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4" "-IC:\\Arduino\\hardware\\teensy\\avr\\libraries\\SPI" "c:\\temp\\arduino_build_359487\\sketch\\ILI9341_t4.cpp" -o "c:\\temp\\arduino_build_359487\\sketch\\ILI9341_t4.cpp.o"
In file included from c:\temp\arduino_build_359487\sketch\ILI9341_t4.cpp:2:0:

C:\Arduino\hardware\teensy\avr\libraries\SPI/SPI.h: In member function 'uint16_t SPIClass::transfer16(uint16_t)':

C:\Arduino\hardware\teensy\avr\libraries\SPI/SPI.h:1168:2: warning: no return statement in function returning non-void [-Wreturn-type]

  }

  ^

Compiling libraries...
Compiling library "SPI"
Zuvor kompilierte Datei wird verwendet: c:\temp\arduino_build_359487\libraries\SPI\SPI.cpp.o
Compiling core...
Using precompiled core: c:\temp\arduino_cache_387431\core\core_teensy_avr_teensy4b_usb_serial,opt_o1std,keys_en-us_b3cedd8ea1410accccb79d4faa089b8a.a
Linking everything together...
"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-gcc" -O1 -Wl,--gc-sections,--relax "-TC:\\Arduino\\hardware\\teensy\\avr\\cores\\teensy4/imxrt.ld" -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -fsingle-precision-constant -o "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.elf" "c:\\temp\\arduino_build_359487\\sketch\\ILI9341_t4.cpp.o" "c:\\temp\\arduino_build_359487\\sketch\\T4_ILI9341.ino.cpp.o" "c:\\temp\\arduino_build_359487\\libraries\\SPI\\SPI.cpp.o" "c:\\temp\\arduino_build_359487/..\\arduino_cache_387431\\core\\core_teensy_avr_teensy4b_usb_serial,opt_o1std,keys_en-us_b3cedd8ea1410accccb79d4faa089b8a.a" "-Lc:\\temp\\arduino_build_359487" -larm_cortexM4lf_math -lm -lstdc++
"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.elf" "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.eep"
"C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-objcopy" -O ihex -R .eeprom "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.elf" "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.hex"
"C:\\Arduino\\hardware\\teensy/../tools/stdout_redirect" "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.lst" "C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-objdump" -d -S -C "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.elf"
"C:\\Arduino\\hardware\\teensy/../tools/stdout_redirect" "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.sym" "C:\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-objdump" -t -C "c:\\temp\\arduino_build_359487/T4_ILI9341.ino.elf"
"C:\\Arduino\\hardware\\teensy/../tools/teensy_post_compile" -file=T4_ILI9341.ino "-path=c:\\temp\\arduino_build_359487" "-tools=C:\\Arduino\\hardware\\teensy/../tools/" -board=TEENSY40
Teensy Loader could not find the file T4_ILI9341.ino

Bibliothek SPI in Version 1.0 im Ordner: C:\Arduino\hardware\teensy\avr\libraries\SPI  wird verwendet
quitexit status 1
Fehler beim Kompilieren für das Board Teensy 4-Beta1.

I don't see any error here..AND no INO file.
I use the memset inside a class function.
If I remove the memset, all works.

Maybe my fault..but I don't see it ?!--pls help :)
Memset is in attached sketch, file ili9341_t4.cpp, line 113
 

Attachments

  • T4_ILI9341-190104a.zip
    2.6 KB · Views: 89
It appears to be complaining about this code in which the return statement has been commented:
Code:
	uint16_t transfer16(uint16_t data) {
		transfer(data >> 8);
		transfer(data & 255);
		//port().SR = SPI_SR_TCF;
		//port().PUSHR = data | SPI_PUSHR_CTAS(1);
		//while (!(port().SR & SPI_SR_TCF)) ; // wait
		//return port().POPR;
	}

P.S. but I don't know why memset would cause this to be compiled.

Pete
 
It's a warning only - I've inserted the return to Pauls SPI Code - the warning disappears, but that does not help..
Attached the sketch to the previous post.

Must be something simple I do not see..
 
The problem occurs as soon as you reference the screen array. If you change your memory clear for loops to just "screen[0][0] = 0;" it will still fail. But if you remove the DMAMEM type from the screen declaration, it will compile and link - don't know why.

Pete
 
Thanks!!! But - now I get
c:/arduino/hardware/tools/arm/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld.exe: c:\temp\arduino_build_403489/T4_ILI9341.ino.elf section `.bss' will not fit in region `DTCM'
c:/arduino/hardware/tools/arm/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld.exe: region `DTCM' overflowed by 37568 bytes
- if it compiles for you, we have different versions(?!)

something must be wrong with my version of the linkerfile.
I'll try a fresh install - have edited some things.
 
I'm using recent, fresh install of Arduino 1.8.8 with TD 1.46_b6 compiling for Teensy 4-Beta1

Pete

Ok, I make a break till tomorrow.. . Did a fresh install of teensyduino (not arduino), still the same:
2019-01-04 21_35_22-Start.jpg
region `DTCM' overflowed by 37568 bytes
 
I don't see a memset in the sketch, but my build does give me the same errors...

But if I comment out the DMAMEM from the array, the build completes:
/*DMAMEM*/ static uint16_t screen[HEIGHT][WIDTH];
 
@el_supremo, don't know why it compiles for you.. and not with my install.
for me, with my installation, it looks like an array this large is not possible at the moment.

time for "dr. who" and a beer. good night.

@Paul:
Bugreport:
Please read the last posts - Two problems: DMAMEM does funny things, big arrays not possible.
In addition, warnings in SPI (missing return) + some more warnings on first compile.

Good news: simple SPI (8bit) transfer works (have not tried reading).
 
DMA using DTCM is problematic. I've already run into the issue a few times, but haven't actually said anything... until now.

I'm not 100% sure of the problem, but my best guess is the ARM processor gets preferred access to DTCM. There doesn't seem to be a fair round-robin arbitration or priority-based scheme like we're used to seeing. I've found code in a tight loop polling a volatile variable can completely stall the USB traffic, for example. NXP has some rather vague guidance to use the OCRAM on the AXI bus for DMA, but they don't say why, only that it's more efficient. My guess is the arbitration is unfavorable to the DMA, and DMA access that does succeed probably isn't nice to code expecting single cycle access to DTCM. The AXI bus is meant for multiple masters. The TCM buses aren't. They're about the ARM having the lowest latency to memory, without other stuff getting in the way.

That's why I put the cache functions into the most recent beta. We really need to start using OCRAM for DMA buffers, including my upcoming rewrite of the USB stuff.

Also needed and on my todo list is assigning the memory partition at startup. Currently we're running with fixed sizes, 128K ITCM, 128K DTCM and 256K OCRAM. I was hoping to put this off until we move to the 1062 chip, since the trade-offs are different with the 2nd OCRAM.
 
Status
Not open for further replies.
Back
Top