Browse Source

Merge pull request #320 from KurtE/T4_SPI_Structure

T4 - SPI - Create structure
teensy4-core
Paul Stoffregen 6 years ago
parent
commit
257bab7ff6
No account linked to committer's email address
2 changed files with 435 additions and 0 deletions
  1. +398
    -0
      teensy4/avr_emulation.h
  2. +37
    -0
      teensy4/imxrt.h

+ 398
- 0
teensy4/avr_emulation.h View File

/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2019 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef _avr_emulation_h_
#define _avr_emulation_h_

#include "imxrt.h"
#include "core_pins.h"
#include "pins_arduino.h"

#ifdef __cplusplus



// SPI Control Register ­ SPCR
#define SPIE 7 // SPI Interrupt Enable - not supported
#define SPE 6 // SPI Enable
#define DORD 5 // DORD: Data Order
#define MSTR 4 // MSTR: Master/Slave Select
#define CPOL 3 // CPOL: Clock Polarity
#define CPHA 2 // CPHA: Clock Phase
#define SPR1 1 // Clock: 3 = 125 kHz, 2 = 250 kHz, 1 = 1 MHz, 0->4 MHz
#define SPR0 0
// SPI Status Register ­ SPSR
#define SPIF 7 // SPIF: SPI Interrupt Flag
#define WCOL 6 // WCOL: Write COLlision Flag - not implemented
#define SPI2X 0 // SPI2X: Double SPI Speed Bit
// SPI Data Register ­ SPDR


class SPCRemulation;
class SPSRemulation;
class SPDRemulation;

class SPCRemulation
{
public:
inline SPCRemulation & operator = (int val) __attribute__((always_inline)) {
/*
uint32_t ctar, mcr, sim6;
//serial_print("SPCR=");
//serial_phex(val);
//serial_print("\n");
sim6 = SIM_SCGC6;
if (!(sim6 & SIM_SCGC6_SPI0)) {
//serial_print("init1\n");
SIM_SCGC6 = sim6 | SIM_SCGC6_SPI0;
SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
}
if (!(val & (1<<SPE))) {
SPI0_MCR |= SPI_MCR_MDIS; // TODO: use bitband for atomic access
}
ctar = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1);
if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE;
if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL;
if (val & (1<<CPHA)) {
ctar |= SPI_CTAR_CPHA;
if ((val & 3) == 0) {
ctar |= SPI_CTAR_BR(1) | SPI_CTAR_ASC(1);
} else if ((val & 3) == 1) {
ctar |= SPI_CTAR_BR(4) | SPI_CTAR_ASC(4);
} else if ((val & 3) == 2) {
ctar |= SPI_CTAR_BR(6) | SPI_CTAR_ASC(6);
} else {
ctar |= SPI_CTAR_BR(7) | SPI_CTAR_ASC(7);
}
} else {
if ((val & 3) == 0) {
ctar |= SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
} else if ((val & 3) == 1) {
ctar |= SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(4);
} else if ((val & 3) == 2) {
ctar |= SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(6);
} else {
ctar |= SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(7);
}
}
ctar |= (SPI0_CTAR0 & SPI_CTAR_DBR);
update_ctar(ctar);
mcr = SPI_MCR_DCONF(0) | SPI_MCR_PCSIS(0x1F);
if (val & (1<<MSTR)) mcr |= SPI_MCR_MSTR;
if (val & (1<<SPE)) {
mcr &= ~(SPI_MCR_MDIS | SPI_MCR_HALT);
SPI0_MCR = mcr;
enable_pins();
} else {
mcr |= (SPI_MCR_MDIS | SPI_MCR_HALT);
SPI0_MCR = mcr;
disable_pins();
}
//serial_print("MCR:");
//serial_phex32(SPI0_MCR);
//serial_print(", CTAR0:");
//serial_phex32(SPI0_CTAR0);
//serial_print("\n");
*/
return *this;
}
inline SPCRemulation & operator |= (int val) __attribute__((always_inline)) {
/*
uint32_t sim6;
//serial_print("SPCR |= ");
//serial_phex(val);
//serial_print("\n");
sim6 = SIM_SCGC6;
if (!(sim6 & SIM_SCGC6_SPI0)) {
//serial_print("init2\n");
SIM_SCGC6 = sim6 | SIM_SCGC6_SPI0;
SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1);
}
if (val & ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) {
uint32_t ctar = SPI0_CTAR0;
if (val & (1<<DORD)) ctar |= SPI_CTAR_LSBFE; // TODO: use bitband
if (val & (1<<CPOL)) ctar |= SPI_CTAR_CPOL;
if (val & (1<<CPHA) && !(ctar & SPI_CTAR_CPHA)) {
ctar |= SPI_CTAR_CPHA;
ctar &= 0xFFFF00FF;
ctar |= SPI_CTAR_ASC(ctar & 15);
}
if ((val & 3) != 0) {
uint32_t br = ctar & 15;
uint32_t priorval;
if (br <= 1) priorval = 0;
else if (br <= 4) priorval = 1;
else if (br <= 6) priorval = 2;
else priorval = 3;
uint32_t newval = priorval | (val & 3);
if (newval != priorval) {
if (newval == 0) br = 1;
else if (newval == 0) br = 4;
else if (newval == 0) br = 6;
else br = 7;
ctar &= 0xFFFF00F0; // clear BR, ASC, CSSCK
if ((ctar & SPI_CTAR_CPHA)) {
ctar |= SPI_CTAR_BR(br) | SPI_CTAR_ASC(br);
} else {
ctar |= SPI_CTAR_BR(br) | SPI_CTAR_CSSCK(br);
}
}
}
update_ctar(ctar);
}
if (val & (1<<MSTR)) SPI0_MCR |= SPI_MCR_MSTR;
if (val & (1<<SPE)) {
SPI0_MCR &= ~(SPI_MCR_MDIS | SPI_MCR_HALT);
enable_pins();
}
//serial_print("MCR:");
//serial_phex32(SPI0_MCR);
//serial_print(", CTAR0:");
//serial_phex32(SPI0_CTAR0);
//serial_print("\n");
*/
return *this;
}
inline SPCRemulation & operator &= (int val) __attribute__((always_inline)) {
/*
//serial_print("SPCR &= ");
//serial_phex(val);
//serial_print("\n");
SIM_SCGC6 |= SIM_SCGC6_SPI0;
if (!(val & (1<<SPE))) {
SPI0_MCR |= (SPI_MCR_MDIS | SPI_MCR_HALT);
disable_pins();
}
if ((val & ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) != ((1<<DORD)|(1<<CPOL)|(1<<CPHA)|3)) {
uint32_t ctar = SPI0_CTAR0;
if (!(val & (1<<DORD))) ctar &= ~SPI_CTAR_LSBFE; // TODO: use bitband
if (!(val & (1<<CPOL))) ctar &= ~SPI_CTAR_CPOL;
if (!(val & (1<<CPHA)) && (ctar & SPI_CTAR_CPHA)) {
ctar &= ~SPI_CTAR_CPHA;
ctar &= 0xFFFF00FF;
ctar |= SPI_CTAR_CSSCK(ctar & 15);
}
if ((val & 3) != 3) {
uint32_t br = ctar & 15;
uint32_t priorval;
if (br <= 1) priorval = 0;
else if (br <= 4) priorval = 1;
else if (br <= 6) priorval = 2;
else priorval = 3;
uint32_t newval = priorval & (val & 3);
if (newval != priorval) {
if (newval == 0) br = 1;
else if (newval == 0) br = 4;
else if (newval == 0) br = 6;
else br = 7;
ctar &= 0xFFFF00F0; // clear BR, ASC, CSSCK
if ((ctar & SPI_CTAR_CPHA)) {
ctar |= SPI_CTAR_BR(br) | SPI_CTAR_ASC(br);
} else {
ctar |= SPI_CTAR_BR(br) | SPI_CTAR_CSSCK(br);
}
}
}
update_ctar(ctar);
}
if (!(val & (1<<MSTR))) SPI0_MCR &= ~SPI_MCR_MSTR;
*/
return *this;
}
inline int operator & (int val) const __attribute__((always_inline)) {
int ret = 0;
/*
//serial_print("SPCR & ");
//serial_phex(val);
//serial_print("\n");
SIM_SCGC6 |= SIM_SCGC6_SPI0;
if ((val & (1<<DORD)) && (SPI0_CTAR0 & SPI_CTAR_LSBFE)) ret |= (1<<DORD);
if ((val & (1<<CPOL)) && (SPI0_CTAR0 & SPI_CTAR_CPOL)) ret |= (1<<CPOL);
if ((val & (1<<CPHA)) && (SPI0_CTAR0 & SPI_CTAR_CPHA)) ret |= (1<<CPHA);
if ((val & 3) != 0) {
uint32_t dbr = SPI0_CTAR0 & 15;
uint32_t spr10;
if (dbr <= 1) {
spr10 = 0;
} else if (dbr <= 4) {
spr10 |= (1<<SPR0);
} else if (dbr <= 6) {
spr10 |= (1<<SPR1);
} else {
spr10 |= (1<<SPR1)|(1<<SPR0);
}
ret |= spr10 & (val & 3);
}
if (val & (1<<SPE) && (!(SPI0_MCR & SPI_MCR_MDIS))) ret |= (1<<SPE);
if (val & (1<<MSTR) && (SPI0_MCR & SPI_MCR_MSTR)) ret |= (1<<MSTR);
//serial_print("ret = ");
//serial_phex(ret);
//serial_print("\n");
*/
return ret;
}
operator int () const __attribute__((always_inline)) {
int ret = 0;
/*
if ((SIM_SCGC6 & SIM_SCGC6_SPI0)) {
int ctar = SPI0_CTAR0;
if (ctar & SPI_CTAR_LSBFE) ret |= (1<<DORD);
if (ctar & SPI_CTAR_CPOL) ret |= (1<<CPOL);
if (ctar & SPI_CTAR_CPHA) ret |= (1<<CPHA);
ctar &= 15;
if (ctar <= 1) {
} else if (ctar <= 4) {
ret |= (1<<SPR0);
} else if (ctar <= 6) {
ret |= (1<<SPR1);
} else {
ret |= (1<<SPR1)|(1<<SPR0);
}
int mcr = SPI0_MCR;
if (!(mcr & SPI_MCR_MDIS)) ret |= (1<<SPE);
if (mcr & SPI_MCR_MSTR) ret |= (1<<MSTR);
}
*/
return ret;
}
inline void setMOSI(uint8_t pin) __attribute__((always_inline)) {
}
inline void setMOSI_soft(uint8_t pin) __attribute__((always_inline)) {
}
inline void setMISO(uint8_t pin) __attribute__((always_inline)) {
}
inline void setSCK(uint8_t pin) __attribute__((always_inline)) {
}
friend class SPSRemulation;
friend class SPIFIFOclass;
private:
static uint8_t pinout;
public:
inline void enable_pins(void) __attribute__((always_inline)) {
//serial_print("enable_pins\n");
}
inline void disable_pins(void) __attribute__((always_inline)) {
}
};
extern SPCRemulation SPCR;


class SPSRemulation
{
public:
inline SPSRemulation & operator = (int val) __attribute__((always_inline)) {
//serial_print("SPSR=");
//serial_phex(val);
//serial_print("\n");
/*
uint32_t ctar = SPI0_CTAR0;
if (val & (1<<SPI2X)) {
ctar |= SPI_CTAR_DBR;
} else {
ctar &= ~SPI_CTAR_DBR;
}
SPCRemulation::update_ctar(ctar);
//serial_print("MCR:");
//serial_phex32(SPI0_MCR);
//serial_print(", CTAR0:");
//serial_phex32(SPI0_CTAR0);
//serial_print("\n");
*/
return *this;
}
inline SPSRemulation & operator |= (int val) __attribute__((always_inline)) {
/*
//serial_print("SPSR |= ");
//serial_phex(val);
//serial_print("\n");
if (val & (1<<SPI2X)) SPCRemulation::update_ctar(SPI0_CTAR0 |= SPI_CTAR_DBR);
*/
return *this;
}
inline SPSRemulation & operator &= (int val) __attribute__((always_inline)) {
/*
//serial_print("SPSR &= ");
//serial_phex(val);
//serial_print("\n");
if (!(val & (1<<SPI2X))) SPCRemulation::update_ctar(SPI0_CTAR0 &= ~SPI_CTAR_DBR);
*/
return *this;
}
inline int operator & (int val) const __attribute__((always_inline)) {
int ret = 0;
//serial_print("SPSR & ");
//serial_phex(val);
//serial_print("\n");
// TODO: using SPI_SR_TCF isn't quite right. Control returns to the
// caller after the final edge that captures data, which is 1/2 cycle
// sooner than AVR returns. At 500 kHz and slower SPI, this can make
// a difference when digitalWrite is used to manually control the CS
// pin, and perhaps it could matter at high clocks if faster register
// access is used? But does it really matter? Do any SPI chips in
// practice really perform differently if CS negates early, after the
// final bit is clocked, but before the end of the whole clock cycle?
if ((val & (1<<SPIF)) && ((LPSPI4_RSR & LPSPI_RSR_RXEMPTY) == 0)) ret = (1<<SPIF);
//if ((val & (1<<SPI2X)) && (SPI0_CTAR0 & SPI_CTAR_DBR)) ret |= (1<<SPI2X);
//delayMicroseconds(50000);
return ret;
}
operator int () const __attribute__((always_inline)) {
int ret = 0;
//serial_print("SPSR (int)\n");
if ((LPSPI4_RSR & LPSPI_RSR_RXEMPTY) == 0) ret = (1<<SPIF);
//if (SPI0_CTAR0 & SPI_CTAR_DBR) ret |= (1<<SPI2X);
return ret;
}
};
extern SPSRemulation SPSR;

class SPDRemulation
{
public:
inline SPDRemulation & operator = (int val) __attribute__((always_inline)) {
//serial_print("SPDR = ");
//serial_phex(val);
//serial_print("\n");
LPSPI4_CR = LPSPI_CR_RRF | LPSPI_CR_MEN; // Module enabled anc clear the receive.
LPSPI4_TDR = (val & 255);
return *this;
}
operator int () const __attribute__((always_inline)) {
uint32_t val;
val = LPSPI4_RDR & 255;
return val;
}
};
extern SPDRemulation SPDR;


#endif // __cplusplus

#endif

+ 37
- 0
teensy4/imxrt.h View File

#define LPI2C_SRDR_DATA(n) ((uint32_t)(((n) & 0xFF) << 0)) #define LPI2C_SRDR_DATA(n) ((uint32_t)(((n) & 0xFF) << 0))


// 38.3.5.2: page 2422 // 38.3.5.2: page 2422
typedef struct {
const uint32_t VERID; // 0
const uint32_t PARAM; // 0x04
const uint32_t UNUSED0; // 0x08
const uint32_t UNUSED1; // 0x0c
volatile uint32_t CR; // 0x10
volatile uint32_t SR; // 0x14
volatile uint32_t IER; // 0x18
volatile uint32_t DER; // 0x1c
volatile uint32_t CFGR0; // 0x20
volatile uint32_t CFGR1; // 0x24
const uint32_t UNUSED3; // 0x28
const uint32_t UNUSED4; // 0x2c
volatile uint32_t DMR0; // 0x30
volatile uint32_t DMR1; // 0x34
const uint32_t UNUSED5; // 0x38
const uint32_t UNUSED6; // 0x3c
volatile uint32_t CCR; // 0x40
const uint32_t UNUSED7; // 0x44
const uint32_t UNUSED8; // 0x48
const uint32_t UNUSED9; // 0x4c
const uint32_t UNUSED10; // 0x50
const uint32_t UNUSED11; // 0x54
volatile uint32_t FCR; // 0x58
volatile uint32_t FSR; // 0x5C
volatile uint32_t TCR; // 0x60
volatile uint32_t TDR; // 0x64
const uint32_t UNUSED12; // 0x68
const uint32_t UNUSED13; // 0x6c
volatile uint32_t RSR; // 0x70
volatile uint32_t RDR; // 0x74
} IMXRT_LPSPI_t;

#define IMXRT_LPSPI1 (*(IMXRT_REGISTER32_t *)0x40394000) #define IMXRT_LPSPI1 (*(IMXRT_REGISTER32_t *)0x40394000)
#define IMXRT_LPSPI1_S (*(IMXRT_LPSPI_t *)0x40394000)
#define LPSPI1_VERID (IMXRT_LPSPI1.offset000) #define LPSPI1_VERID (IMXRT_LPSPI1.offset000)
#define LPSPI1_PARAM (IMXRT_LPSPI1.offset004) #define LPSPI1_PARAM (IMXRT_LPSPI1.offset004)
#define LPSPI1_CR (IMXRT_LPSPI1.offset010) #define LPSPI1_CR (IMXRT_LPSPI1.offset010)
#define LPSPI1_RSR (IMXRT_LPSPI1.offset070) #define LPSPI1_RSR (IMXRT_LPSPI1.offset070)
#define LPSPI1_RDR (IMXRT_LPSPI1.offset074) #define LPSPI1_RDR (IMXRT_LPSPI1.offset074)
#define IMXRT_LPSPI2 (*(IMXRT_REGISTER32_t *)0x40398000) #define IMXRT_LPSPI2 (*(IMXRT_REGISTER32_t *)0x40398000)
#define IMXRT_LPSPI2_S (*(IMXRT_LPSPI_t *)0x40398000)
#define LPSPI2_VERID (IMXRT_LPSPI2.offset000) #define LPSPI2_VERID (IMXRT_LPSPI2.offset000)
#define LPSPI2_PARAM (IMXRT_LPSPI2.offset004) #define LPSPI2_PARAM (IMXRT_LPSPI2.offset004)
#define LPSPI2_CR (IMXRT_LPSPI2.offset010) #define LPSPI2_CR (IMXRT_LPSPI2.offset010)
#define LPSPI2_RSR (IMXRT_LPSPI2.offset070) #define LPSPI2_RSR (IMXRT_LPSPI2.offset070)
#define LPSPI2_RDR (IMXRT_LPSPI2.offset074) #define LPSPI2_RDR (IMXRT_LPSPI2.offset074)
#define IMXRT_LPSPI3 (*(IMXRT_REGISTER32_t *)0x4039C000) #define IMXRT_LPSPI3 (*(IMXRT_REGISTER32_t *)0x4039C000)
#define IMXRT_LPSPI3_S (*(IMXRT_LPSPI_t *)0x4039C000)
#define LPSPI3_VERID (IMXRT_LPSPI3.offset000) #define LPSPI3_VERID (IMXRT_LPSPI3.offset000)
#define LPSPI3_PARAM (IMXRT_LPSPI3.offset004) #define LPSPI3_PARAM (IMXRT_LPSPI3.offset004)
#define LPSPI3_CR (IMXRT_LPSPI3.offset010) #define LPSPI3_CR (IMXRT_LPSPI3.offset010)
#define LPSPI3_RSR (IMXRT_LPSPI3.offset070) #define LPSPI3_RSR (IMXRT_LPSPI3.offset070)
#define LPSPI3_RDR (IMXRT_LPSPI3.offset074) #define LPSPI3_RDR (IMXRT_LPSPI3.offset074)
#define IMXRT_LPSPI4 (*(IMXRT_REGISTER32_t *)0x403A0000) #define IMXRT_LPSPI4 (*(IMXRT_REGISTER32_t *)0x403A0000)
#define IMXRT_LPSPI4_S (*(IMXRT_LPSPI_t *)0x403A0000)
#define LPSPI4_VERID (IMXRT_LPSPI4.offset000) #define LPSPI4_VERID (IMXRT_LPSPI4.offset000)
#define LPSPI4_PARAM (IMXRT_LPSPI4.offset004) #define LPSPI4_PARAM (IMXRT_LPSPI4.offset004)
#define LPSPI4_CR (IMXRT_LPSPI4.offset010) #define LPSPI4_CR (IMXRT_LPSPI4.offset010)

Loading…
Cancel
Save