Sam D21 SPI Interface - Bare Code

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all!

 

I need to control a Digital Potentiometer MPC41010 through SPI in SAM D21.

My code needs to increase or decrease (0 to 255) through Button 1 and Button 2 of OLED1 Xplained Pro to SPI Potentiometer. 

I did read of Buttons and ok, then my code needs to put in Data register for transmit but no success.

 

Today I read the DS and I am confusing in some things.

 

Anyone has a Bare Code in exemple for SPI interface? Then I can study it based in datasheet. I have no found any example in internet. 

 

Thanks!

Paulo

 

 

Franc

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ASF provides SPI examples.

 

Also examples of using the OLED1 XPro.

 

Take them as your starting point.

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear awneil, I need it in Bare Code. 

Thanks

Franc

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you used the display on the the OLED1 Xplained Board?

It uses SPI.

What have you tried?

David

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 4

Bare code here, but note most likely you will want to control the chip select manually (and not using the SERCOM SPI like in the example).  So MSSEN=0 and not setting up pin muxing for that pin (PA18 in the example).

#include "sam.h"

void spiInit(void)
{
    PM->APBCMASK.bit.SERCOM1_ = 1;
    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID_SERCOM1_CORE;
    while(GCLK->STATUS.bit.SYNCBUSY);
    const SERCOM_SPI_CTRLA_Type ctrla = {
      .bit.DORD = 0, // MSB first
      .bit.CPHA = 0, // Mode 0
      .bit.CPOL = 0,
      .bit.FORM = 0, // SPI frame
      .bit.DIPO = 3, // MISO on PAD[3]
      .bit.DOPO = 0, // MOSI on PAD[0], SCK on PAD[1], SS_ on PAD[2]
      .bit.MODE = 3  // Master
    };
    SERCOM1->SPI.CTRLA.reg = ctrla.reg;
    const SERCOM_SPI_CTRLB_Type ctrlb = {
      .bit.RXEN = 1,   // RX enabled
      .bit.MSSEN = 1,  // HW SS
      .bit.CHSIZE = 0 // 8-bit
    };
    SERCOM1->SPI.CTRLB.reg = ctrlb.reg;	

    SERCOM1->SPI.BAUD.reg = 0; // Rate is clock / 2 

    // Mux for SERCOM1 PA16,PA17,PA18,PA19
    const PORT_WRCONFIG_Type wrconfig = {
      .bit.WRPINCFG = 1,
      .bit.WRPMUX = 1,
      .bit.PMUX = MUX_PA16C_SERCOM1_PAD0,
      .bit.PMUXEN = 1,
      .bit.HWSEL = 1,
      .bit.PINMASK = (uint16_t)((PORT_PA16 | PORT_PA17 | PORT_PA18 | PORT_PA19) >> 16)
    };
    PORT->Group[0].WRCONFIG.reg = wrconfig.reg;

    SERCOM1->SPI.CTRLA.bit.ENABLE = 1;
    while(SERCOM1->SPI.SYNCBUSY.bit.ENABLE);
}

uint8_t spiSend(uint8_t data)
{
    while(SERCOM1->SPI.INTFLAG.bit.DRE == 0);
    SERCOM1->SPI.DATA.reg = data;
    while(SERCOM1->SPI.INTFLAG.bit.RXC == 0);
    return SERCOM1->SPI.DATA.reg;
}

int main(void)
{
    SystemInit();
    spiInit();

    volatile uint8_t rData;
    volatile uint8_t sData = 0;
    while (1) {
      rData = spiSend(sData++);
    }
}

/Lars

 

Last Edited: Fri. Oct 28, 2016 - 06:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank so much friends. I will check this bare code. Regards!

Franc

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

eletrocampos wrote:
I need it in Bare Code.

I said take it as your starting point ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks so much for this SPI setup code.  I just tried it and it works perfectly.

 

-troy

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, thanks Lars for posting the example code. The example code works for me, but when I try to change it to work for SERCOM0 with MOSI on pad0 (PA08), SCLK on pad1 (PA09), CS on pad2 (PA10), and MISO on pad3 (PA11). When I run in debug mode all the code executes and seems to run, but none of the pins are outputting anything which makes me think I am not setting up the pins or pin mux correctly. Below is my code, would greatly appreciate any help.

 

void spiInitSERCOM0(void)
{
	PM->APBCMASK.bit.SERCOM0_ = 1;
	GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID_SERCOM0_CORE;
	while(GCLK->STATUS.bit.SYNCBUSY);
	const SERCOM_SPI_CTRLA_Type ctrla = {
		.bit.DORD = 0, // MSB first
		.bit.CPHA = 0, // Mode 0
		.bit.CPOL = 0,
		.bit.FORM = 0, // SPI frame
		.bit.DIPO = 3, // MISO on PAD[3]
		.bit.DOPO = 0, // MOSI on PAD[0], SCK on PAD[1], SS_ on PAD[2]
		.bit.MODE = 3  // Master
	};
	SERCOM0->SPI.CTRLA.reg = ctrla.reg;
	const SERCOM_SPI_CTRLB_Type ctrlb = {
		.bit.RXEN = 1,   // RX enabled
		.bit.MSSEN = 1,  // HW SS
		.bit.CHSIZE = 0 // 8-bit
	};
	SERCOM0->SPI.CTRLB.reg = ctrlb.reg;

	SERCOM0->SPI.BAUD.reg = 0; // Rate is clock / 2

	// Mux for SERCOM0 PA08,PA09,PA10,PA11
	const PORT_WRCONFIG_Type wrconfig = {
		.bit.WRPINCFG = 1,
		.bit.WRPMUX = 1,
		.bit.PMUX = MUX_PA08C_SERCOM0_PAD0,
		.bit.PMUXEN = 1,
		.bit.HWSEL = 0,
		.bit.PINMASK = (uint16_t)((PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11) >> 16)
	};
	PORT->Group[0].WRCONFIG.reg = wrconfig.reg;

	SERCOM0->SPI.CTRLA.bit.ENABLE = 1;
	while(SERCOM0->SPI.SYNCBUSY.bit.ENABLE);
}

uint8_t spiSend0(uint8_t data)
{
	while(SERCOM0->SPI.INTFLAG.bit.DRE == 0);
	SERCOM0->SPI.DATA.reg = data;
	while(SERCOM0->SPI.INTFLAG.bit.RXC == 0);
	return SERCOM0->SPI.DATA.reg;
}

int main(void)
{
	SystemInit();
	spiInitSERCOM0();
	delay_init();

	volatile uint8_t rData;
	volatile uint8_t sData = 0;
	while (1) {
		delay_ms(1);
		rData = spiSend0(MAX31856_CONFIG_REG);
		rData |= MAX31856_CONFIG_3WIRE;
		//spiSend1(rData);
	}
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are configuring pins with HWSEL 0 which is correct for the PA08-PA11, but you need to remove the 

>> 16)

for PINMASK, it was needed for PA16-PA19 with HWSEL 1.

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That makes sense and it worked. Thank you Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey guys! 

Just to add on, trying to get something similar working and having some trouble. Any help would be great!! 

 

MCP41100, only SPI sending, not receiving. 

 

using PA00 MOSI, PA01 for SCK. I'm manually flipping the CS pin in code. 

 

void spiInitSERCOM1(void)
{
    PM->APBCMASK.bit.SERCOM1_ = 1;
    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID_SERCOM1_CORE;
    while(GCLK->STATUS.bit.SYNCBUSY);
    const SERCOM_SPI_CTRLA_Type ctrla = {
        .bit.DORD = 0, // MSB first
        .bit.CPHA = 0, // Mode 0
        .bit.CPOL = 0,
        .bit.FORM = 0, // SPI frame
        .bit.DIPO = 3, // MISO on PAD[3]
        .bit.DOPO = 0, // MOSI on PAD[0], SCK on PAD[1], SS_ on PAD[2]
        .bit.MODE = 3  // Master
    };
    SERCOM1->SPI.CTRLA.reg = ctrla.reg;
    const SERCOM_SPI_CTRLB_Type ctrlb = {
        .bit.RXEN = 1,   // RX enabled
        .bit.MSSEN = 1,  // HW SS
        .bit.CHSIZE = 0 // 8-bit
    };
    SERCOM1->SPI.CTRLB.reg = ctrlb.reg;

    SERCOM1->SPI.BAUD.reg = 0; // Rate is clock / 2

    // Mux for SERCOM1
    const PORT_WRCONFIG_Type wrconfig = {
        .bit.WRPINCFG = 1,
        .bit.WRPMUX = 1,
        .bit.PMUX = MUX_PA00D_SERCOM1_PAD0,
        .bit.PMUXEN = 1,
        .bit.HWSEL = 0,
        .bit.PINMASK = (uint16_t)((PORT_PA00 | PORT_PA01 | PORT_PA30 | PORT_PA31))
        };
    PORT->Group[0].WRCONFIG.reg = wrconfig.reg;

    SERCOM1->SPI.CTRLA.bit.ENABLE = 1;
    while(SERCOM1->SPI.SYNCBUSY.bit.ENABLE);
}

 

// here I'm trying to consolidate the process since 0x11 has to be sent everytime you write to the digital pot and I'm not writing to anything else. 

uint8_t spiSend0(uint8_t data)
{
    while(SERCOM1->SPI.INTFLAG.bit.DRE == 0);
    SERCOM1->SPI.DATA.reg = 0x11;
    while(SERCOM1->SPI.INTFLAG.bit.DRE == 0);
    SERCOM1->SPI.DATA.reg = data;

}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't say what is not working but I notice a problem with the port setting: WRCONFIG can't configure your pins with one register write, you need one write for PA00,PA01 (HWSEL = 0) and one for PA30,PA31 (HWSEL = 1 and the bitmasks shifted down 16).
/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also not sure exactly what is not working, I'm trying to bare code this but have a atmel start version that works so I know my physical connections are right.  

 

 

definitely made a error there, pa30 and 31 aren't the right pins for sercom 1. Since I dont need pa18,pa19 do I just leave them off?  Since they are below 16 there is no bit shift right? 

 

      .bit.PINMASK = (uint16_t)((PORT_PA00 | PORT_PA01))

 

thanks!