1 /*!
2  * \file      spi-board.c
3  *
4  * \brief     Target board SPI driver implementation
5  *
6  * \copyright Revised BSD License, see section \ref LICENSE.
7  *
8  * \code
9  *                ______                              _
10  *               / _____)             _              | |
11  *              ( (____  _____ ____ _| |_ _____  ____| |__
12  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
13  *               _____) ) ____| | | || |_| ____( (___| | | |
14  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
15  *              (C)2013-2017 Semtech
16  *
17  * \endcode
18  *
19  * \author    Miguel Luis ( Semtech )
20  *
21  * \author    Gregory Cristian ( Semtech )
22  *
23  * \author    Marten Lootsma(TWTG) on behalf of Microchip/Atmel (c)2017
24  */
25 #include <peripheral_clk_config.h>
26 #include <hal_spi_m_sync.h>
27 #include <hal_gpio.h>
28 #include "spi-board.h"
29 
30 struct spi_m_sync_descriptor Spi0;
31 
SpiInit(Spi_t * obj,SpiId_t spiId,PinNames mosi,PinNames miso,PinNames sclk,PinNames nss)32 void SpiInit( Spi_t *obj, SpiId_t spiId, PinNames mosi, PinNames miso, PinNames sclk, PinNames nss )
33 {
34     hri_gclk_write_PCHCTRL_reg( GCLK, SERCOM4_GCLK_ID_CORE, CONF_GCLK_SERCOM4_CORE_SRC | ( 1 << GCLK_PCHCTRL_CHEN_Pos ) );
35     hri_gclk_write_PCHCTRL_reg( GCLK, SERCOM4_GCLK_ID_SLOW, CONF_GCLK_SERCOM4_SLOW_SRC | ( 1 << GCLK_PCHCTRL_CHEN_Pos ) );
36 
37     hri_mclk_set_APBCMASK_SERCOM4_bit( MCLK );
38 
39     spi_m_sync_init( &Spi0, SERCOM4 );
40 
41     hri_sercomspi_wait_for_sync( SERCOM4, SERCOM_SPI_SYNCBUSY_SWRST );
42     hri_sercomspi_set_CTRLA_SWRST_bit( SERCOM4 );
43     hri_sercomspi_wait_for_sync( SERCOM4, SERCOM_SPI_SYNCBUSY_SWRST );
44     // 0x0001000C DOPO=1 MODE=3
45     hri_sercomspi_write_CTRLA_reg( SERCOM4, SERCOM_SPI_CTRLA_MODE( 3 ) | SERCOM_SPI_CTRLA_DOPO( 1 ) );
46     // 0x00020000 RXEN
47     hri_sercomspi_write_CTRLB_reg( SERCOM4, SERCOM_SPI_CTRLB_RXEN );
48     hri_sercomspi_write_BAUD_reg( SERCOM4, ( ( float )CONF_GCLK_SERCOM4_CORE_FREQUENCY / ( float )( 2 * 1000000 ) ) - 1 );
49     hri_sercomspi_write_DBGCTRL_reg( SERCOM4, 0 );
50 
51     // Set pin direction to input. MISO
52     gpio_set_pin_direction( miso, GPIO_DIRECTION_IN );
53     gpio_set_pin_pull_mode( miso, GPIO_PULL_OFF );
54     gpio_set_pin_function( miso, PINMUX_PC19F_SERCOM4_PAD0 );
55 
56     // Set pin direction to output. MOSI
57     gpio_set_pin_direction( mosi, GPIO_DIRECTION_OUT );
58     gpio_set_pin_level( mosi, false );
59     gpio_set_pin_function( mosi, PINMUX_PB30F_SERCOM4_PAD2 );
60 
61     // Set pin direction to output. CLK
62     gpio_set_pin_direction( sclk, GPIO_DIRECTION_OUT );
63     gpio_set_pin_level( sclk,  false );
64     gpio_set_pin_function( sclk, PINMUX_PC18F_SERCOM4_PAD3 );
65 
66     hri_sercomspi_set_CTRLA_ENABLE_bit( SERCOM4 );
67 }
68 
SpiDeInit(Spi_t * obj)69 void SpiDeInit( Spi_t *obj )
70 {
71     GpioInit( &obj->Mosi, obj->Mosi.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
72     GpioInit( &obj->Miso, obj->Miso.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_DOWN, 0 );
73     GpioInit( &obj->Sclk, obj->Sclk.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
74     GpioInit( &obj->Nss, obj->Nss.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 1 );
75 }
76 
SpiInOut(Spi_t * obj,uint16_t outData)77 uint16_t SpiInOut( Spi_t *obj, uint16_t outData )
78 {
79     // Wait for bus idle (ready to write)
80     while( ( SERCOM_SPI_INTFLAG_DRE & hri_sercomspi_read_INTFLAG_reg( SERCOM4 ) ) == 0 )
81     {
82 
83     }
84     hri_sercomspi_clear_INTFLAG_reg( SERCOM4, SERCOM_SPI_INTFLAG_DRE );
85 
86     // Write byte
87     hri_sercomspi_write_DATA_reg( SERCOM4, outData );
88 
89     // Wait for ready to read
90     while( ( SERCOM_SPI_INTFLAG_RXC & hri_sercomspi_read_INTFLAG_reg( SERCOM4 ) ) == 0 )
91     {
92 
93     }
94     hri_sercomspi_clear_INTFLAG_reg( SERCOM4, SERCOM_SPI_INTFLAG_RXC );
95 
96     // Read byte
97     outData = ( uint16_t )hri_sercomspi_read_DATA_reg( SERCOM4 );
98 
99     return outData;
100 }
101