Teensy 4.0 First Beta Test

Status
Not open for further replies.
Yes, I provided setClockFreq snippet (post #454). If you look at the ref manual, the CCR DIV is treated as +2, so if DIV is 0, peripheral clock is divided by 2. If DIV is 1, clock is divided by 3 ... So if you want the clock divided by 8, you put 6 in the CCR DIV field.
Thanks Tom, and for the explanation, getting tired of looking at that manual. Too many posts, think I agree with Frank - need sub-forums.

The discrete SPI dividers for 75 mhz are 2,3,4,5 .... which gives SPI CLK of 37.5, 25, 18.75 ... the setClockFreq algorithm picks the divider less than or equal to user-requested frequency
Noticed I ran a test sketch and put in various clock frequencies just to see.
 
Maybe Ethernet? I just tried to compile Ethernet udpntp example, i get compile errors, undefined reference to `vtable for IPAddress', but I have other domestic chores in the next few hours ...
This vtable error is some sort of C++ thingee above my old C skills. Here is the simplest program that gets compile errors on T4, works on T3.2. (I believe i have copied in stream.cpp and WString.cpp into my T4 core folder)
Code:
#include <IPAddress.h>
IPAddress ip(192, 168, 1, 15);
void setup() {
  Serial.begin(9600);
  while(!Serial);
  delay(1000);
  Serial.println(ip);
}

void loop() {
}
 
Last edited:
Other things to be done: set/get time, start and sync HPRTC and test alarm, core set-time logic

Added alarm on LPRTC (official manual does not give information but CMSIS/Keil etc give other addresses)
OK, got Alarm firing
AND
LPRTC Alarm can indeed be used to restart program after "Turn off System Power" command
Without additional actions (clock etc) consumption drops from 80 mA while running to 25 mA while System Power Off.
 
Added alarm on LPRTC (official manual does not give information but CMSIS/Keil etc give other addresses)
OK, got Alarm firing
AND
LPRTC Alarm can indeed be used to restart program after "Turn off System Power" command
Without additional actions (clock etc) consumption drops from 80 mA while running to 25 mA while System Power Off.

Excellent! I was looking at doing that this morning. But you have left too much to the imagination ... can you post/github your demo code?
 
Last edited:
SPI: What was the reason to choose 7? (528000000/7) isn't 2 much better?
I'd really really like to change this... would be better for everything. SD for example can't reach 25MHz now, because ther is one slightly higher 25.1 MHZ - the next step is 18.8 MHz.
With 2 we could have 24MHz - so..why this 7?

Edit: Just tested with SD - works.

I'd like to add a function that allows to set this. This would be most flexible.
 
Last edited:
Excellent! I was looking at doing that this morning. But you have left too much to the imagination ... can you post/github your demo code?

Here it comes.
Code:
#include <time.h>
/*  
  int  tm_sec;
  int tm_min;
  int tm_hour;
  int tm_mday;
  int tm_mon;
  int tm_year;
  int tm_wday;
  int tm_yday;
  int tm_isdst;
*/
// following routines are based on http://howardhinnant.github.io/date_algorithms.html
struct tm seconds2tm(uint32_t tt)
{ struct tm tx;
  tx.tm_sec   = tt % 60;    tt /= 60; // now it is minutes
  tx.tm_min   = tt % 60;    tt /= 60; // now it is hours
  tx.tm_hour  = tt % 24;    tt /= 24; // now it is days
  tx.tm_wday  = ((tt + 4) % 7) ;      // Sunday is day 0
  //
  tt += 719468;
  uint32_t era = (tt >= 0 ? tt : tt - 146096) / 146097;
  uint32_t doe = (tt - era * 146097);                             // [0, 146096]
  uint32_t yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
  uint32_t yy = (yoe) + era * 400;
  uint32_t doy = doe - (365*yoe + yoe/4 - yoe/100);            // [0, 365]
  uint32_t mp = (5*doy + 2)/153;                               // [0, 11]
  uint32_t dd = doy - (153*mp+2)/5 + 1;                        // [1, 31]
  uint32_t mm = mp + (mp < 10 ? 3 : -9);                       // [1, 12]
//
  tx.tm_year=yy + (mm <= 2);
  tx.tm_mday=dd;
  tx.tm_mon=mm;
  return tx;
}

uint32_t tm2seconds(struct tm tx)
{
  uint32_t yy = tx.tm_year;
  uint32_t mm = tx.tm_mon;
  uint32_t dd = tx.tm_mday;
  
  yy -= mm <= 2;
  uint32_t era = (yy >= 0 ? yy : yy-399) / 400;
  uint32_t yoe = (yy - era * 400);      // [0, 399]
  uint32_t doy = (153*(mm + (mm > 2 ? -3 : 9)) + 2)/5 + dd-1;  // [0, 365]
  uint32_t doe = yoe * 365 + yoe/4 - yoe/100 + doy;         // [0, 146096]

  uint32_t tt = era * 146097 + (doe) - 719468;
  tt *= (24*3600);
  tt += (tx.tm_hour*60+tx.tm_min)*60+tx.tm_sec;

  return tt;
}

/*********************************************************************************/
// see also https://github.com/manitou48/teensy4/blob/master/rtc.ino
#define SNVS_DEFAULT_PGD_VALUE (0x41736166U)
#define SNVS_LPSR_PGD_MASK                       (0x8U)
#define SNVS_LPSRTCMR      (IMXRT_SNVS.offset050)
#define SNVS_LPSRTCLR      (IMXRT_SNVS.offset054)
//----------------------------------------------------
#define SNVS_LPTAR        (IMXRT_SNVS.offset058)

#define SNVS_LPCR_SRTC_ENV_MASK         (0x1U)
#define SNVS_LPCR_SRTC_ENV(x)           (((uint32_t)(((uint32_t)(x)) << 0U)) & SNVS_LPCR_SRTC_ENV_MASK)

#define SNVS_LPCR_LPTA_EN_MASK          (0x2U)
#define SNVS_LPCR_LPTA_EN(x)            (((uint32_t)(((uint32_t)(x)) << 1U)) & SNVS_LPCR_LPTA_EN_MASK)

#define SNVS_LPCR_MC_ENV_MASK           (0x4U)
#define SNVS_LPCR_MC_ENV(x)             (((uint32_t)(((uint32_t)(x)) << 2U)) & SNVS_LPCR_MC_ENV_MASK)

#define SNVS_LPCR_LPWUI_EN_MASK         (0x8U)
#define SNVS_LPCR_LPWUI_EN(x)           (((uint32_t)(((uint32_t)(x)) << 3U)) & SNVS_LPCR_LPWUI_EN_MASK)

#define SNVS_LPCR_SRTC_INV_EN_MASK      (0x10U)
#define SNVS_LPCR_SRTC_INV_EN(x)        (((uint32_t)(((uint32_t)(x)) << 4U)) & SNVS_LPCR_SRTC_INV_EN_MASK)

#define SNVS_LPCR_DP_EN_MASK            (0x20U)
#define SNVS_LPCR_DP_EN(x)              (((uint32_t)(((uint32_t)(x)) << 5U)) & SNVS_LPCR_DP_EN_MASK)

#define SNVS_LPCR_TOP_MASK              (0x40U)
#define SNVS_LPCR_TOP(x)                (((uint32_t)(((uint32_t)(x)) << 6U)) & SNVS_LPCR_TOP_MASK)

#define SNVS_LPCR_PWR_GLITCH_EN_MASK    (0x80U)
#define SNVS_LPCR_PWR_GLITCH_EN(x)      (((uint32_t)(((uint32_t)(x)) << 7U)) & SNVS_LPCR_PWR_GLITCH_EN_MASK)

#define SNVS_LPCR_LPCALB_EN_MASK        (0x100U)
#define SNVS_LPCR_LPCALB_EN(x)          (((uint32_t)(((uint32_t)(x)) << 8U)) & SNVS_LPCR_LPCALB_EN_MASK)

#define SNVS_LPCR_LPCALB_VAL_MASK       (0x7C00U)
#define SNVS_LPCR_LPCALB_VAL(x)         (((uint32_t)(((uint32_t)(x)) << 10U)) & SNVS_LPCR_LPCALB_VAL_MASK)

#define SNVS_LPCR_BTN_PRESS_TIME_MASK   (0x30000U)
#define SNVS_LPCR_BTN_PRESS_TIME(x)     (((uint32_t)(((uint32_t)(x)) << 16U)) & SNVS_LPCR_BTN_PRESS_TIME_MASK)

#define SNVS_LPCR_DEBOUNCE_MASK         (0xC0000U)
#define SNVS_LPCR_DEBOUNCE(x)           (((uint32_t)(((uint32_t)(x)) << 18U)) & SNVS_LPCR_DEBOUNCE_MASK)

#define SNVS_LPCR_ON_TIME_MASK          (0x300000U)
#define SNVS_LPCR_ON_TIME(x)            (((uint32_t)(((uint32_t)(x)) << 20U)) & SNVS_LPCR_ON_TIME_MASK)

#define SNVS_LPCR_PK_EN_MASK            (0x400000U)
#define SNVS_LPCR_PK_EN(x)              (((uint32_t)(((uint32_t)(x)) << 22U)) & SNVS_LPCR_PK_EN_MASK)

#define SNVS_LPCR_PK_OVERRIDE_MASK      (0x800000U)
#define SNVS_LPCR_PK_OVERRIDE(x)        (((uint32_t)(((uint32_t)(x)) << 23U)) & SNVS_LPCR_PK_OVERRIDE_MASK)

#define SNVS_LPCR_GPR_Z_DIS_MASK        (0x1000000U)
#define SNVS_LPCR_GPR_Z_DIS(x)          (((uint32_t)(((uint32_t)(x)) << 24U)) & SNVS_LPCR_GPR_Z_DIS_MASK)

#define SNVS_LPSR_LPTA                  (0x1U)

void rtc_init() 
{ CCM_CCGR2 |= CCM_CCGR2_IOMUXC_SNVS(CCM_CCGR_ON);
  SNVS_LPGPR = SNVS_DEFAULT_PGD_VALUE;
  SNVS_LPSR = SNVS_LPSR_PGD_MASK;
  // ? calibration
  // ? tamper pins
  
  SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK; // clear alarm
  while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK); 
  SNVS_LPTAR=0;

  SNVS_LPCR |= 1;             // start RTC
  while (!(SNVS_LPCR & 1));
}

extern void *__rtc_localtime; 
void rtc_set_time(uint32_t secs) 
{ //uint32_t secs = 1547051415;
  SNVS_LPCR &= ~1;   // stop RTC
  while (SNVS_LPCR & 1);
  SNVS_LPSRTCMR = (uint32_t)(secs >> 17U);
  SNVS_LPSRTCLR = (uint32_t)(secs << 15U);
  SNVS_LPCR |= 1;             // start RTC
  while (!(SNVS_LPCR & 1));
}

uint32_t rtc_secs() {
  uint32_t seconds = 0;
  uint32_t tmp = 0;

  /* Do consecutive reads until value is correct */
  do
  { seconds = tmp;
    tmp = (SNVS_LPSRTCMR << 17U) | (SNVS_LPSRTCLR >> 15U);
  } while (tmp != seconds);

  return seconds;
}

void rtc_stopAlarm()
{
  SNVS_LPSR |= 1;
  SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
  while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK); 
}
void rtc_isr(void)
{ 
  SNVS_LPSR |= 1;
  Serial.println("Alarm");
  asm("DSB"); // needed? what does it
}

void rtc_initAlarm(uint32_t prio=13)
{
  attachInterruptVector(IRQ_SNVS_IRQ, rtc_isr);
  NVIC_SET_PRIORITY(IRQ_SNVS_IRQ, prio*16); // 8 is normal priority
  NVIC_DISABLE_IRQ(IRQ_SNVS_IRQ);
}

void rtc_setAlarm(uint32_t alarmSeconds)
{   uint32_t tmp = SNVS_LPCR; //save control register

    /* disable SRTC alarm interrupt */
    rtc_stopAlarm();

    SNVS_LPTAR=alarmSeconds;
    while(SNVS_LPTAR != alarmSeconds);

    NVIC_ENABLE_IRQ(IRQ_SNVS_IRQ);

    SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK; // restore control register and set alarm
    while(!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK)); 
}

uint32_t rtc_getAlarm()
{
  return SNVS_LPTAR;  
}

void doShutdown(void) 
{ 
  SNVS_LPCR |=(1<<6);
}

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Start");
  rtc_init();
  if((uint32_t)&__rtc_localtime> (rtc_secs()+10))
    rtc_set_time((uint32_t)&__rtc_localtime);   //LPSRTC will start at 0 otherwise
  rtc_initAlarm(13);
}

void loop() {
  static int count=0;
  struct tm tx;
  uint32_t t0 = rtc_secs();
  tx=seconds2tm(t0);
  uint32_t t1 = tm2seconds(tx);
  Serial.printf("%d %d : ",t0,t1);
  Serial.printf("%4d-%02d-%02d %02d:%02d:%02d - %d\n",
                tx.tm_year,tx.tm_mon,tx.tm_mday, tx.tm_hour,tx.tm_min,tx.tm_sec,
                tx.tm_wday);
  delay(1000);
  count++;
  if(count==50)
  {
    uint32_t t0 = rtc_secs();
    Serial.println("Stop");
    rtc_setAlarm(t0+60);
    Serial.printf("Alarm: ");  Serial.println(rtc_getAlarm());
    Serial.println("Shutdown");
    doShutdown();
    Serial.println("Reset");
  }
}
 
SPI: What was the reason to choose 7? (528000000/7) isn't 2 much better?
..
I'd like to add a function that allows to set this. This would be most flexible.

Yup. I'll create a pullrequest for a additional function. I really hope Paul accepts it :) 3 would allow 58.7 Mhz.
Code:
[TABLE="width: 804"]
[TR]
[TD]PLL2[/TD]
[TD="align: right"]528000000[/TD]
[TD][/TD]
[TD][/TD]
[TD][/TD]
[TD][/TD]
[TD][/TD]
[TD]*[/TD]
[TD][/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD][/TD]
[TD="align: right"]2[/TD]
[TD="align: right"]3[/TD]
[TD="align: right"]4[/TD]
[TD="align: right"]5[/TD]
[TD="align: right"]6[/TD]
[TD="align: right"]7[/TD]
[TD="align: right"]8[/TD]
[TD]CBCMR LPSPI[/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]1[/TD]
[TD="align: right"]264000000[/TD]
[TD="align: right"]176000000[/TD]
[TD="align: right"]132000000[/TD]
[TD="align: right"]105600000[/TD]
[TD="align: right"]88000000[/TD]
[TD="align: right"]75428571,4[/TD]
[TD="align: right"]66000000[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]2[/TD]
[TD="align: right"]132,0[/TD]
[TD="align: right"]88,0[/TD]
[TD="align: right"]66,00[/TD]
[TD="align: right"]52,80[/TD]
[TD="align: right"]44,00[/TD]
[TD="align: right"]37,71[/TD]
[TD="align: right"]33,00[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]3[/TD]
[TD="align: right"]88,0[/TD]
[TD="align: right"]58,7[/TD]
[TD="align: right"]44,00[/TD]
[TD="align: right"]35,20[/TD]
[TD="align: right"]29,33[/TD]
[TD="align: right"]25,14[/TD]
[TD="align: right"]22,00[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]4[/TD]
[TD="align: right"]66,0[/TD]
[TD="align: right"]44,0[/TD]
[TD="align: right"]33,00[/TD]
[TD="align: right"]26,40[/TD]
[TD="align: right"]22,00[/TD]
[TD="align: right"]18,86[/TD]
[TD="align: right"]16,50[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]5[/TD]
[TD="align: right"]52,8[/TD]
[TD="align: right"]35,2[/TD]
[TD="align: right"]26,40[/TD]
[TD="align: right"]21,12[/TD]
[TD="align: right"]17,60[/TD]
[TD="align: right"]15,09[/TD]
[TD="align: right"]13,20[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]6[/TD]
[TD="align: right"]44,0[/TD]
[TD="align: right"]29,3[/TD]
[TD="align: right"]22,00[/TD]
[TD="align: right"]17,60[/TD]
[TD="align: right"]14,67[/TD]
[TD="align: right"]12,57[/TD]
[TD="align: right"]11,00[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]7[/TD]
[TD="align: right"]37,7[/TD]
[TD="align: right"]25,1[/TD]
[TD="align: right"]18,86[/TD]
[TD="align: right"]15,09[/TD]
[TD="align: right"]12,57[/TD]
[TD="align: right"]10,78[/TD]
[TD="align: right"]9,43[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]8[/TD]
[TD="align: right"]33,0[/TD]
[TD="align: right"]22,0[/TD]
[TD="align: right"]16,50[/TD]
[TD="align: right"]13,20[/TD]
[TD="align: right"]11,00[/TD]
[TD="align: right"]9,43[/TD]
[TD="align: right"]8,25[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]9[/TD]
[TD="align: right"]29,3[/TD]
[TD="align: right"]19,6[/TD]
[TD="align: right"]14,67[/TD]
[TD="align: right"]11,73[/TD]
[TD="align: right"]9,78[/TD]
[TD="align: right"]8,38[/TD]
[TD="align: right"]7,33[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]10[/TD]
[TD="align: right"]26,4[/TD]
[TD="align: right"]17,6[/TD]
[TD="align: right"]13,20[/TD]
[TD="align: right"]10,56[/TD]
[TD="align: right"]8,80[/TD]
[TD="align: right"]7,54[/TD]
[TD="align: right"]6,60[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]11[/TD]
[TD="align: right"]24,0[/TD]
[TD="align: right"]16,0[/TD]
[TD="align: right"]12,00[/TD]
[TD="align: right"]9,60[/TD]
[TD="align: right"]8,00[/TD]
[TD="align: right"]6,86[/TD]
[TD="align: right"]6,00[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]12[/TD]
[TD="align: right"]22,0[/TD]
[TD="align: right"]14,7[/TD]
[TD="align: right"]11,00[/TD]
[TD="align: right"]8,80[/TD]
[TD="align: right"]7,33[/TD]
[TD="align: right"]6,29[/TD]
[TD="align: right"]5,50[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]13[/TD]
[TD="align: right"]20,3[/TD]
[TD="align: right"]13,5[/TD]
[TD="align: right"]10,15[/TD]
[TD="align: right"]8,12[/TD]
[TD="align: right"]6,77[/TD]
[TD="align: right"]5,80[/TD]
[TD="align: right"]5,08[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]14[/TD]
[TD="align: right"]18,9[/TD]
[TD="align: right"]12,6[/TD]
[TD="align: right"]9,43[/TD]
[TD="align: right"]7,54[/TD]
[TD="align: right"]6,29[/TD]
[TD="align: right"]5,39[/TD]
[TD="align: right"]4,71[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]15[/TD]
[TD="align: right"]17,6[/TD]
[TD="align: right"]11,7[/TD]
[TD="align: right"]8,80[/TD]
[TD="align: right"]7,04[/TD]
[TD="align: right"]5,87[/TD]
[TD="align: right"]5,03[/TD]
[TD="align: right"]4,40[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]255[/TD]
[TD="align: right"]1,0[/TD]
[TD="align: right"]0,7[/TD]
[TD="align: right"]0,52[/TD]
[TD="align: right"]0,41[/TD]
[TD="align: right"]0,35[/TD]
[TD="align: right"]0,30[/TD]
[TD="align: right"]0,26[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]256[/TD]
[TD="align: right"]1,0[/TD]
[TD="align: right"]0,7[/TD]
[TD="align: right"]0,52[/TD]
[TD="align: right"]0,41[/TD]
[TD="align: right"]0,34[/TD]
[TD="align: right"]0,29[/TD]
[TD="align: right"]0,26[/TD]
[TD][/TD]
[/TR]
[TR]
[TD][/TD]
[TD="align: right"]257[/TD]
[TD="align: right"]1,0[/TD]
[TD="align: right"]0,7[/TD]
[TD="align: right"]0,51[/TD]
[TD="align: right"]0,41[/TD]
[TD="align: right"]0,34[/TD]
[TD="align: right"]0,29[/TD]
[TD="align: right"]0,26[/TD]
[TD][/TD]
[/TR]
[/TABLE]
 

Attachments

  • teensy4_pll2_spi.zip
    7.8 KB · Views: 78
Last edited:
SPI: What was the reason to choose 7? (528000000/7) isn't 2 much better?
I'd really really like to change this... would be better for everything. SD for example can't reach 25MHz now, because ther is one slightly higher 25.1 MHZ - the next step is 18.8 MHz.
With 2 we could have 24MHz - so..why this 7?

Edit: Just tested with SD - works.

I'd like to add a function that allows to set this. This would be most flexible.

You should be able to run SPI at 37.5 mhz (ask for 40 mhz in spisettings). Paul made the choice of 528000000/7. It could be a smaller divider. On the EVKB SDK tests we were using 528000000/5, max SPI clock of 52.8 mhz. The setClockFrequency code is hardcoded with 528000000/7, so that would need to changed with variables or define's. base clock is set in SPI.cpp
CCM_CBCMR = (CCM_CBCMR & ~(CCM_CBCMR_LPSPI_PODF_MASK | CCM_CBCMR_LPSPI_CLK_SEL_MASK)) |
CCM_CBCMR_LPSPI_PODF(6) | CCM_CBCMR_LPSPI_CLK_SEL(2);

PODF is divider -1
 
Last edited:
Yes i've seen the / 7 - it's simple to use the CBCMR register-value instead. Then, the user has the _chance_ to change it.. without modifiying the SPI library.
In addition a small function to change the CBCMR LPSPI, and all is perfect.
 
Hey Frank. Just made your change changed PDOF to 1 and the divider to 2 in spi settings. Th measured clk freq is 29.41Mhz vs 25.41mhz at current settings.

Ok, missed your post.

EDIT: just checked with 3. No real difference in the frequency of 29.41

EDIT: At 60Mhz getting 57.14Mhz, Mosi waveform looks good as well.
 
Hey Frank. Just made your change changed PDOF to 1 and the divider to 2 in spi settings. Th measured clk freq is 29.41Mhz vs 25.41mhz at current settings.

Ok, missed your post.

EDIT: just checked with 3. No real difference in the frequency of 29.41

EDIT: At 60Mhz getting 57.14Mhz, Mosi waveform looks good as well.

I've posted a table .. :)
Edit: With excel sheet.
 
I've posted a table .. :)
Edit: With excel sheet.

That math looks better Frank - more options at the ~30 MHz sweetspot - and possibilities on the higher end. Nice to have a steady background clock versus on F_CPU or F_BUS - how many htings would change that do feed off the PLL clock? Will that let T4 UART Serial get over 5.33 MBaud?
 
Adafruit_ILI9341

Starting looking at the adafruit library and was wondering if someone could explain to me what the advantages are of doing this instead of setting the pins. Guessing its faster:

Code:
    clkport     = portOutputRegister(digitalPinToPort(_sclk));
    clkpinmask  = digitalPinToBitMask(_sclk);
    mosiport    = portOutputRegister(digitalPinToPort(_mosi));
    mosipinmask = digitalPinToBitMask(_mosi);
    *clkport   &= ~clkpinmask;
    *mosiport  &= ~mosipinmask;

These are of course are throwings errors for conversion.
 
was wondering if someone could explain to me what the advantages are of doing this instead of setting the pins. Guessing its faster:

Yup, it's faster.

On many of these Adafruit libs that do direct I/O, we're going to have to deal with the GPIO registers now being only 32 bits. Fortunately in the last few years many other boards have appeared that have 32 bit registers, so most of the libs now have stuff in place. The situation isn't as terrible as a few years ago when everything assumed I/O registers must be 8 bits.

Of course, on Teensy 3.x the GPIO registers were also 32 bits. But there are 2 important differences. The main one is the M4's bitband. On Teensy 3.x, these functions do not give you the actual GPIO register address, but rather the bitband address for just 1 pin. The bitband allows any size access, even though the data is only in the lowest bit, so this ancient code that assumes all GPIO is 8 bit registers is perfectly happy talking to the bitband. Using the bitband also solves non-atomic read-modify-write bugs that Adafruit is probably unaware exist, which libraries doing read-modify-write for different bits in the same registers, from interrupts, can cause havoc. I really miss the bitband. :(

The other difference on Teensy 3.x is the GPIO registers do allow 8 bit access. You'll just write to the low 8 bits, and the upper 24 bits remain unchanged.

Sadly, NXP made the GPIO only 32 bits in this new chip, and ARM didn't put the bitband into M7. I believe most of these Adafruit libs using this direct GPIO access can be ported pretty easily. The main problem is going to be they probably have #ifdef checks that make the registers 8 bits for Teensy 3.x.
 
Oh, that wasn't ever meant to be any sort of official decision. It was just something I did very quickly, so we could have a minimal-but-working SPI library to start testing.

This value has to be choosen carefully, I think...
Please shout if I say something wrong: SD-Cards want initialization with 400Khz, and they accept 25MHz for datatransfer. 25.1Mhz are probably fine, too.
I've tried 1MHz initialization with two cards, and they work, but probably not all cards are happy with that..

Now, this can be important: If we have TWO SPI in the future, we just can't change this clock - it affects both SPIs.
If we have ONE SPI, no problem - then, we can calculate the best value for each transaction.
So... Paul... ONE or TWO? ;)
 
Sadly, NXP made the GPIO only 32 bits in this new chip, and ARM didn't put the bitband into M7. I believe most of these Adafruit libs using this direct GPIO access can be ported pretty easily. The main problem is going to be they probably have #ifdef checks that make the registers 8 bits for Teensy 3.x.
Actually other than setting up the pins not sure they are doing anything else with them in terms of graphics. The display commands and writes link back to Adafruit GFX library. Taking a quick look have to sort it out - nothing straight forward.
 
CAPACITIVE SENSOR LIBRARY

Initial testing:
1. Doesn't work on a T3.2, tried as a test
2. On the T4, it does work sort of. By this I mean the values changes as I touch the copper foil, and change depending on how long I hold my finger down or how much of my finger touches the foil. But - the readings come out about ever 2000 ms vs the 15 in your video (yes I looked). Using 1M resistor for send and 1k for receive (couldn't find any 4.7Ms.
3. Even without anything attached readings were 2secs apart.

Have not looked at the code yet just wanted to report the results so far.

EDIT: In all honesty the resistors aren't soldered to the foil, I have foil that is conductive on both sides so I just taped them down. I did measure the resistance from the foil to the other side of the resistor and did read 1M and 1K.
 
@Paul
ADAFRUIT ILI9341 and GFX Libraries

Just visited the Adafruit GitHub pages for those two libraries. Looks like there was a update a couple-three months ago that add 32-bit reg support. Essentially they re-worked their libraries. You may want to update the Teensyduino versions. Going to download and take a look at the updated libararies.

Mike

UPDATE: GOOD NEWS. The updated Adafruit library works with the T4 - attached a ILI9341 and ran the graphicstest sketch - worked with no changes to the library. Thanks for the hint Paul.

Code:
ILI9341 Test!
Display Power Mode: 0x94
MADCTL Mode: 0x48
Pixel Format: 0x5
Image Format: 0x80
Self Diagnostic: 0xC0
Benchmark                Time (microseconds)
Screen fill              2253160
Text                     107910
Lines                    1024400
Horiz/Vert Lines         183970
Rectangles (outline)     117020
Rectangles (filled)      4676300
Circles (filled)         525140
Circles (outline)        448120
Triangles (outline)      233750
Triangles (filled)       1516370
Rounded rects (outline)  216620
Rounded rects (filled)   4648490
Done!
Don't have anything to compare it too so if someone else would like to post. going to run a few more tests but have to go do something now.
 
Last edited:
SPI.cpp work to do:

I ran SPI test with SerialFlash on T3.4 and T4. Despite T4 clock running at 37 mhz and T3.2 only at 30 mhz, the T3.2 did faster page reads than T4 (83 us vs 129us). T3 SPI lib is optimized to use FIFO so there are 16-bit transfers with small interframe gap (76ns). The T4 SPI still needs to be optimized, since it does simple byte transfers with 260 ns interframe gap. So T4 SPI needs to use its FIFO and/or 16 or 32-bit frame size. Also SPI.cpp needs T4 support of async/DMA transfer.

EDIT: Kurt had pending pull-request (now merged) to use FIFO. I need to re-run SerialFlash test ...
 
Last edited:
ADAFRUIT ILI9341 and GFX Libraries

Well, can no longer update my previous post on testing the libraries, but I just tried to load a bitmap example and the image did not load. As you all probably know it uses PROGMEM. The image format is set up as:
Code:
const PROGMEM uint16_t dragonBitmap[DRAGON_WIDTH * DRAGON_HEIGHT] = {
  0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
I don't think there is a problem with the format or space. Just checking before digging into the code

EDIT:
Got an interesting error when I was trying to load purple.c gimp image:
Code:
f:/arduino-1.8.8-t4/hardware/tools/arm/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld.exe: region `DTCM' overflowed by 37568 bytes
 
Last edited:
I'm almost done with a library for watchdog. It will enable a watchdog output on pins 19 or 20 that after a watchdog reboot will keep the pin states LOW until an actual user reset is applied. I also added callback support, trying to finish it off soon :)
 
IntervalTimer

Would it be possible to have the channel member of the IntervalTimer protected instead of private? The old "cast to IRQ_Number" trick doesn't work anymore since the T4 only has one IRQ for all channels.
 
Status
Not open for further replies.
Back
Top