SPI for SAMD10 not working - Page 1
Forum section: electronics / general

author: n4alpaca
author_rank: Newbie
timestamp: January 07, 2018, 01:19:50 am
content: Hello, I've been playing around with a broken out micro controller (SAMD10) for some time and lately I've been struggling with SPI. Everything seems to be set alright, but I'm not getting any output (I check physical pins 9 and 10 of the SOIC package) on PA22 or PA23. I've included the code in question and pictures of the registers for each step. It seems as though SPI is functioning, but I'm not seeing any output.MainCode:int main(void) {sys_init();struct PIN doSPI = gpio_create_pin(PMUXC,MUX_ENABLE,PORTA,22,OUT,PULLUP,PULL_DISABLE,IN_DISABLE);struct PIN sckSPI = gpio_create_pin(PMUXD,MUX_ENABLE,PORTA,23,OUT,PULLUP,PULL_DISABLE,IN_DISABLE);struct PIN diSPI = gpio_create_pin(PMUXC,MUX_ENABLE,PORTA,25,IN,PULLUP,PULL_DISABLE,IN_ENABLE);init_SPI(BAUD9600,0x0u,0x3u,LSB,0x0u,MASTER,FALSE,200,200);do {//uart_puts("C");spi_putc('C');} while (1);return 0;}SPI initializationCode:void init_SPI(BAUD baud,uint8_t dopo,uint8_t dipo,TX_ORDER ord, uint8_t format, MASTER_SEL masterSel, BOOLEAN addrMode, uint8_t addr, uint8_t addrMask){__enable_irq();NVIC_EnableIRQ( DMAC_IRQn );NVIC_EnableIRQ( EVSYS_IRQn );uint32_t br = (uint64_t)65536 * (F_CPU - 16 * baud) / F_CPU;PM->APBCMASK.reg |= PM_APBCMASK_SERCOM1; // enable powerGCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM1_GCLK_ID_CORE) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0x1ul);if(masterSel == 0){masterSel = 0x2u;}else{masterSel = 0x3; // default as master}if(format == 2){format = 0x2u; // SPI frame with address (first byte of message is checked)}else{0x0u; // default to SPI frame without address}if(dopo > 3 || dopo < 0){dopo = 0x0u;dipo = 0x3u;}if(dipo > 3 || dipo < 0){dopo = 0x0u;dipo = 0x3u;}if(addrMode > 2 || addrMode < 0){//0 is addr in addrmask, 1 is addr and addrmask, 2 is a range between addr and addrmaskaddrMode = 0x0u;}SERCOM1->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(masterSel) | SERCOM_SPI_CTRLA_CPOL | (SERCOM_SPI_CTRLA_DORD & ord) | SERCOM_SPI_CTRLA_DIPO(dopo) | SERCOM_SPI_CTRLA_DIPO(dipo) | SERCOM_SPI_CTRLA_FORM(format);SERCOM1->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_RXEN | SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_AMODE(addrMode);SERCOM1->SPI.ADDR.reg = 0x0u;SERCOM1->SPI.ADDR.reg |= SERCOM_SPI_ADDR_ADDR(addr);SERCOM1->SPI.ADDR.reg |= SERCOM_SPI_ADDR_ADDRMASK(addrMask);SERCOM1->SPI.BAUD.reg = (uint8_t)br+1;SERCOM1->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;/* SERCOM 1Pad Pin MuxPad PA_22 CPad PA_30 CPad PA_23 CPad PA_31 CPad PA_08 CPad PA_16 CPad PA_30 DPad PA_24 CPad PA_09 CPad PA_17 CPad PA_31 DPad PA_25 C*//* Data In PinoutDIPO Pad0x0 Pad0x1 Pad0x2 Pad0x3 Pad*//* Data Out PinoutDOPO Data Out SCK slave_ss0x0 Pad Pad Pad0x1 Pad Pad Pad0x2 Pad Pad Pad0x3 Pad Pad Pad*/}//-----------------------------------------------------------------------------void spi_putc(char c){while (!(SERCOM1->SPI.INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE));SERCOM1->SPI.DATA.reg = (uint16_t)c;}int spi_getc(){if (SERCOM1->SPI.INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC) {return SERCOM1->SPI.DATA.reg;}return -1;}//-----------------------------------------------------------------------------void spi_puts(const char *s){while (*s)uart_putc(*s++);}Setting GCLK:Initialize CTRLA:Initialize CTRLBCTRLA enabled:Before Send Data:After Send Data:

author: ataradov
author_rank: Super Contributor
timestamp: January 07, 2018, 02:11:38 am
content: Do you actually have Clock Generator 1 configured and enabled?

author: rstofer
author_rank: Super Contributor
timestamp: January 07, 2018, 02:22:31 am
content: Do you need to enable SERCOM1?

author: ataradov
author_rank: Super Contributor
timestamp: January 07, 2018, 02:23:26 am
content: Quote from: rstofer on January 07, 2018, 02:22:31 amHe does:Quote

author: ajb
author_rank: Super Contributor
timestamp: January 07, 2018, 05:08:37 am
content: If the DRE flag is changing, that suggests that the SERCOM is getting a clock. What does the gpio_create_pin function do? Looks like it creates a struct representing the pin settings, but does it actually apply those settings? Have you verified that the pin registers are being set correctly?I don't think this is your main problem right now, but I think your baud rate calculation is wrong. Datasheet says that SPI mode uses the synchronous baud generator mode.

author: ataradov
author_rank: Super Contributor
timestamp: January 07, 2018, 05:11:34 am
content: Quote from: ajb on January 07, 2018, 05:08:37 amNot necessarily. Depends on what clock domain that bit is in.Double check that this bit ever gets set back again and the loop is looping.

author: n4alpaca
author_rank: Newbie
timestamp: January 08, 2018, 02:49:56 am
content: Hello,Alex: I used the uart_init method from your samd10 as a reference and I guess I forgot to link the genclk to a source with the GENCTRL register.I added:Code:GCLK->CLKCTRL.reg |= GCLK_CLKCTRL_ID(SERCOM1_GCLK_ID_CORE) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(GCLK_CLKCTRL_GEN_GCLK1_Val);And now I have output on the data out pin, but for some reason not the SCLK pin. I haven't had too much time this weekend to devote to debugging this, but I will be able to spend some time this week.ajb: Yes, my baud calculation is wrong. The baud calculation is a point of confusion for me. The data sheet specifies that for synchronous mode the calculation should result in an 8-bit number, however my calculation results in a 9-bit number. The equation they give is BAUD = (fref / (2 * fbaud)) where fref is the frequency from the GCLK (8MHz in this case), fbaud is the baud rate as a frequency I think and BAUD is the value to be put into the register which would give the corresponding baud rate.My fref is 8MHz if as I have disabled the prescaler. The baud I would like is 9600 which equates to 9600Hz. so plugging in the numbers gives 417(rounded). If I'm not mistaken, the solution is to to divide this gclk by 8.I added:Code:uint32_t br = (uint16_t)((F_CPU/8)/(baud*2)) - 1;GCLK->GENDIV.reg = GCLK_GENDIV_ID(GCLK_CLKCTRL_GEN_GCLK1_Val) | GCLK_GENDIV_DIV(8);

author: ataradov
author_rank: Super Contributor
timestamp: January 08, 2018, 02:54:57 am
content: Quote from: n4alpaca on January 08, 2018, 02:49:56 amYou can just specify 0 as the generator in the SERCOM code. EDIT: but not if you need a divider, of course.Quote from: n4alpaca on January 08, 2018, 02:49:56 amThat looks more like PORT configuration problem, and with your port initialization functions, I have no idea what might be wrong.Quote from: n4alpaca on January 08, 2018, 02:49:56 amTo get super low baudrates on SPI you have to divide peripheral clock, as you did.But it is very strange to have such low frequencies on the synchronous interface. What's your application for this?

author: n4alpaca
author_rank: Newbie
timestamp: January 08, 2018, 03:14:37 am
content: I'll be going over the port configuration stuff hopefully on Tuesday. I have no specific application as of yet. I'm just trying to familiarize myself with programming micro-controllers. I'm looking to try to involve myself with some kind of process automation projects soon (I dabble in hydroponics, so that's likely where I'll start).EDIT: accidentally wrote PMUXD instead of PMUXC, the clock outputs just fine

author: ataradov
author_rank: Super Contributor
timestamp: January 08, 2018, 03:17:41 am
content: Quote from: n4alpaca on January 08, 2018, 03:14:37 amIn that case for most real application your BR setting will be 0, 1, or 2. And that's for 48 MHz operation. If you are running at 8 MHz, just stick with BR=0. I doubt there are any SPI devices that can't handle 4 MHz.