Skip to content

Commit

Permalink
Initial SSC (SPI) serial support.
Browse files Browse the repository at this point in the history
  • Loading branch information
sburford committed Aug 12, 2016
1 parent d56e468 commit d3e8d70
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 23 deletions.
5 changes: 4 additions & 1 deletion src/examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LDFLAGS_SRAM=-T ../linker.sram.ld -nostartfiles
LIBC=-L /usr/lib/arm-none-eabi/newlib/armv6-m -lc

all: ultrasonic.elf speed_test.elf temp.elf two_phase_pwm.elf eru.elf \
eru_ccu.elf
eru_ccu.elf usic_ssc_mode.elf
@echo "done"

MAIN_LIBS=../init.o ../peripherals/scu.o \
Expand Down Expand Up @@ -40,6 +40,9 @@ SPEED_TEST_LIBS=../init.o ../peripherals/scu.o \
speed_test.elf: $(SPEED_TEST_LIBS) speed_test.o
$(LD) $(LDFLAGS_SRAM) --cref -Map $@.map $^ -o $@

usic_ssc_mode.elf: $(SPEED_TEST_LIBS) ../peripherals/systick.o usic_ssc_mode.o
$(LD) $(LDFLAGS_SRAM) --cref -Map $@.map $^ -o $@

TEMPERATURE_LIBS=../init.o ../peripherals/ccu.o \
../peripherals/scu.o ../peripherals/gpio.o \
../peripherals/nvic.o ../peripherals/systick.o \
Expand Down
4 changes: 2 additions & 2 deletions src/examples/speed_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ static unsigned int txcount = 0;

void usicCh0Receive(unsigned int val) {
val = val & 0xFF;
*USIC0_CH0_IN = val;
USIC0_CH0_IN[0] = val;
if ((unsigned char)val == '\r') {
*USIC0_CH0_IN = '\n';
USIC0_CH0_IN[0] = '\n';
}
if (val == 'x') {
txcount = 115200;
Expand Down
90 changes: 90 additions & 0 deletions src/examples/usic_ssc_mode.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Send characters to/from a USIC SSC port.

// Configure USIC channel 1 as an SSC master using pins:
// DX0 input: P0.6 (USIC_CH1.DX0C)
// DOUT0 output: P0.7 (P0.7 ALT7)
// SCLKOUT output: P0.8 (P0.8 ALT7)
// CS SELO0 output: P0.9 (P0.9 ALT7)


#include "xmc1100.h"
#include "peripherals/gpio.h"
#include "peripherals/nvic.h"
#include "peripherals/scu.h"
#include "peripherals/systick.h"
#include "peripherals/usic.h"
#include "peripherals/usic_fifo.h"

void __attribute__((interrupt("IRQ"))) systickHandler(void) {
unsigned int rbufsr = 0;
unsigned int rbuf = 0;
char buff[64];

togglePinP1(0);

// MCP3008 expects 1 start bit, sgl/diff and then a 3 bit channel.
// In return it:
// misses a clock
// sends a zero
// sends a 10 bit MSB conversion.
// We're 7 bits in before the conversion value starts coming, so we should
// lose one bit with our 16 bit read.
USIC0_CH1_TBUF[1] = (unsigned short) 0xC800; // 1 (start) 1 (single) 000 (ch0)
while (USIC0_CH1_TCSR & 0x80)
;
USIC0_CH1_TBUF[1] = (unsigned short) 0x0000; // clock in more data

rbufsr = USIC0_CH1_RBUFSR;
if (rbufsr & (BIT13 | BIT14)) {
while (rbufsr & (BIT13 | BIT14)) {
rbuf = USIC0_CH1_RBUF;
toHex(rbufsr, &buff[0]);
buff[8] = ' ';
toHex(rbuf, &buff[9]);
buff[13] = '\r';
buff[14] = '\n';
buff[15] = '\0';
usicBufferedSendCh0(buff);
rbufsr = USIC0_CH1_RBUFSR;
}
usicBufferedSendCh0(&buff[13]);
}
}

int main()
{
scuPostReset(CLKCR_M32_P64);

// On board LEDs.
enablePin(1, 0, GPIO_OUT_PP);
enablePin(1, 1, GPIO_OUT_PP);

// Pins used for USIC channel 0 ASC mode.
enablePin(2, 1, GPIO_OUT_PP_ALT6); // USIC0_CH0_DOUT0
enablePin(2, 2, GPIO_IN_FLOAT); // debug serial input
clearPin(1, 0);
clearPin(1, 1);

// Pins used for USIC channel 1 SSC mode.
enablePin(0, 6, GPIO_IN_FLOAT); // DX0C in
enablePin(0, 7, GPIO_OUT_PP_ALT7); // data out
enablePin(0, 8, GPIO_OUT_PP_ALT7); // sclk out
enablePin(0, 9, GPIO_OUT_PP_ALT7); // chip select out

while (usicConfigure(0, USIC_PROTO_ASC) ||
usicFifoEnable(0) ||
usicConfigure(1, USIC_PROTO_SSC)) {
asm("wfi");
}

systickEnable(8000000 - 1);

enable_interrupts();

usicBufferedSendCh0("Ready.\r\n");
while(1)
{
asm("wfi");
}
return 0;
}
124 changes: 104 additions & 20 deletions src/peripherals/usic.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,98 @@ unsigned int usicChannelBase(int channel) {
return cbase;
}

static void usicConfigureSSCMaster(const unsigned int cbase,
const unsigned int wlen) {
// Configure USIC channel 1 as an SSC master using pins:
// DX0 input: P0.6 (USIC_CH1.DX0C)
// DOUT0 output: P0.7 (P0.7 ALT7)
// SCLKOUT output: P0.8 (P0.8 ALT7)
// CS SELO0 output: P0.9 (P0.9 ALT7)
// Channel 1 XMC2Go available pins:
// DX0 input is available on P0.6, P0.7, P2.10, P2.11
// DOUT0 is available on P0.6, P0.7, P2.10, P2.11
// SCLKOUT is available on P0.8, P2.11
// CS SELO0 is available on P0.0 or P0.9
// No other CS SELO? line is exposed.

// Baud rate config for SCLK.
// fsclk = fsys(32MHz) * (STEP/1024) * 1/2 * 1/(PDIV + 1)
// using scripts/serial_solver.py we find a good fractional solution
// that provides exactly 100K and 400k baud fsclk values:
// step=0x300 PCTQ=1 DCTQ=9 PDIV=0xB 100000 PDIV=2 400000
// Max baud rate for these values is 1.2M.
USIC0_FDR(cbase) = 0x00008300; // Fractional mode, STEP=0x300
// SCLKCFG=01, PDIV=000B, DCTQ=9, PCTQ=1
USIC0_BRG(cbase) = (1 << 30) | (0x000B << 16) | (9 << 10) | (1<<8);

// Shift control register.
USIC0_SCTR(cbase) = ((16-1) << 24) | // SCTR.WLE (word length)
((wlen-1) << 16) | // SCTR.FLE (frame length)
(1 << 8) | // SCTR.TRM (1: shift idle at 1)
(0 << 6) | // SCTR.DOCFG (0: DOUTx not inverted)
(0 << 4) | // SCTR.HPCDIR (0: hwcontrol=input
(0 << 2) | // SCTR.DSM (0: one bit at a time)
(1 << 1) | // SCTR.PDL (1: passive data level 1)
(1 << 0); // SCTR.SDIR (1: shift MSB first)

// Transmission control and status register.
USIC0_TCSR(cbase) = (1 << 10) | // TCSR.TDEN (01: TBUFx valid if TDV)
//(1 << 1) | // TCSR.SELMD (1: TBUFx selects CS)
(1 << 8); // TCSR.TDSSM (1: invalidate sent data)

// SSC Protocol Control Register.
USIC0_PCR(cbase) = (1 << 16) | // PCR.SELO (1: SELO0 can be used)
(0 << 8) | // PCR.DCTQ1 (0: 1/fctqin)
(0 << 6) | // PCR.PCTQ1 (0: 1/fctqin)
(2 << 4) | // PCR.CTQSEL1 (2: fctqin = fsclk)
(0 << 3) | // PCR.FEM (0: Frame ends when TX ends)
(1 << 2) | // PCR.SELINV (1: CS is active low)
(1 << 1) | // PCR.SELCTR (1: direct select mode)
(1 << 0); // PCR.MSLSEN (1: master use slave select)

// DX0 data input.
USIC0_DX0CR(cbase) = (0 << 8) | // DX0CR.DPOL (0: signal isnt inverted)
(1 << 4) | // DX0CR.INSW (1: no PPU processing)
(2 << 0); // DX0CR.DSEL = DXnC (P0.6)
// DX1 clock input (to data shift unit).
// Not used in master mode, PPP provides clock for data shift unit.
USIC0_DX1CR(cbase) = 0;
// DX2 chip select input (to data shift unit).
// Not used in master mode, PPP provides select and delay for the DSU.
USIC0_DX2CR(cbase) = 0;
}

static void usicConfigureASC(const unsigned int cbase) {
// For clock = 32MHz:
// Fractional mode, STEP=0x24E
// PDIV=0004, DCTQ=15, PCTQ=1 (PDIV=4 for 115200 baud,
// PDIV=3B for 9600)
USIC0_FDR(cbase) = 0x0000824E;
USIC0_BRG(cbase) = (0x0004 << 16) | (15 << 10) | (1<<8);
// 8 bits, active high, passive high
// USIC0_SCTR(cbase) = 0x07070102;
USIC0_SCTR(cbase) = ((8-1) << 24) | // SCTR.WLE (word length)
((8-1) << 16) | // SCTR.FLE (frame length)
(1 << 8) | // SCTR.TRM (1: shift idle at 1)
(0 << 6) | // SCTR.DOCFG (0: DOUTx not inverted)
(0 << 4) | // SCTR.HPCDIR (0: hwcontrol=input
(0 << 2) | // SCTR.DSM (0: one bit at a time)
(1 << 1) | // SCTR.PDL (1: passive data level 1)
(0 << 0); // SCTR.SDIR (0: shift LSB first)
// TDSSM=1: TBUF is considered invalid when moved to shift reg
// TDEN=1: TBUF is considered valid when it gets assigned
USIC0_TCSR(cbase) = 0x00000500; // TDSSM=1, TDEN=01
// majority bit decision, 1 stop, sample at 9
USIC0_PCR(cbase) = (9 << 8) | 1;
// TODO: This is only correct for CH0 to the XMC2Go pins.
USIC0_DX3CR(cbase) = 0x00000000; // DX3 DXnA selected (P2.2)
USIC0_DX0CR(cbase) = 0x00000006; // DX0 DXnG selected, fPeriph
}

static void usicConfigureIIC(const unsigned int cbase) {
;
}

unsigned int usicConfigure(int channel, int protocol) {
const unsigned int cbase = usicChannelBase(channel);
if (cbase == 0)
Expand All @@ -108,32 +200,24 @@ unsigned int usicConfigure(int channel, int protocol) {
unsigned int proto_available = BIT6 | BIT7; // RB, TB buffers
unsigned int ccr_enable = 0;
switch(protocol) {
case USIC_PROTO_SSC:
proto_available |= BIT0;
// SSC
ccr_enable = USIC_PROTO_SSC;
usicConfigureSSCMaster(cbase, 32); // XXX
break;
case USIC_PROTO_ASC:
proto_available |= BIT1;
// ASC, no hardware control, no parity.
ccr_enable = USIC_PROTO_ASC;

// For clock = 32MHz:
// Fractional mode, STEP=0x24E
// PDIV=0004, DCTQ=15, PCTQ=1 (PDIV=4 for 115200 baud,
// PDIV=3B for 9600)
USIC0_FDR(cbase) = 0x0000824E;
USIC0_BRG(cbase) = (0x0004 << 16) | (15 << 10) | (1<<8);
// 8 bits, active high, passive high
USIC0_SCTR(cbase) = 0x07070102;
// TDSSM=1: TBUF is considered invalid when moved to shift reg
// TDEN=1: TBUF is considered valid when it gets assigned
USIC0_TCSR(cbase) = 0x00000500; // TDSSM=1, TDEN=01
// majority bit decision, 1 stop, sample at 9
USIC0_PCR(cbase) = (9 << 8) | 1;
// TODO: This is only correct for CH0 to the XMC2Go pins.
USIC0_DX3CR(cbase) = 0x00000000; // DX3 DXnA selected (P2.2)
USIC0_DX0CR(cbase) = 0x00000006; // DX0 DXnG selected, fPeriph
usicConfigureASC(cbase);
break;
case USIC_PROTO_IIC:
proto_available |= BIT2;
// IIC, parity must be disabled.
ccr_enable = USIC_PROTO_IIC;
usicConfigureIIC(cbase);
break;
default:
return 1;
}
Expand All @@ -143,7 +227,7 @@ unsigned int usicConfigure(int channel, int protocol) {
return 1;
}

// Generally use default interrupt routing.
// Use default interrupt routing.
USIC0_INPR(cbase) = 0;

// Enable the protocol unit.
Expand All @@ -155,9 +239,9 @@ unsigned int usicConfigure(int channel, int protocol) {
// Input character handler, may be overridden by the user.
void __attribute__((weak)) usicCh0Receive(unsigned int val) {
val = val & 0xFF;
*USIC0_CH0_IN = val;
USIC0_CH0_IN[0] = val;
if ((unsigned char)val == '\r') {
*USIC0_CH0_IN = '\n';
USIC0_CH0_IN[0] = '\n';
}
}

Expand Down

0 comments on commit d3e8d70

Please sign in to comment.