243 lines
7.9 KiB
C
243 lines
7.9 KiB
C
/**
|
|
* \file
|
|
*
|
|
* \brief Application implement
|
|
*
|
|
* Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries.
|
|
*
|
|
* \asf_license_start
|
|
*
|
|
* \page License
|
|
*
|
|
* Subject to your compliance with these terms, you may use Microchip
|
|
* software and any derivatives exclusively with Microchip products.
|
|
* It is your responsibility to comply with third party license terms applicable
|
|
* to your use of third party software (including open source software) that
|
|
* may accompany Microchip software.
|
|
*
|
|
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
|
|
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
|
|
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
|
|
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
|
|
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
|
|
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
|
|
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
|
|
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
|
|
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
|
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
|
*
|
|
* \asf_license_stop
|
|
*
|
|
*/
|
|
/*
|
|
* Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
|
|
*/
|
|
|
|
#include <atmel_start.h>
|
|
#include "driver_examples.h"
|
|
#include "spi_slave_dma_config.h"
|
|
|
|
/* DMA channel for SPI Slave TX and RX */
|
|
#define CONF_SERCOM_6_TRANSMIT_DMA_CHANNEL 2
|
|
#define CONF_SERCOM_6_RECEIVE_DMA_CHANNEL 3
|
|
|
|
/* Buffer length to transfer/receive */
|
|
#define BUFFER_LEN (12)
|
|
|
|
/* DMA channel Descriptor */
|
|
extern DmacDescriptor _descriptor_section[DMAC_CH_NUM];
|
|
extern DmacDescriptor _write_back_section[DMAC_CH_NUM];
|
|
|
|
/* IO descriptor for SPI master */
|
|
struct io_descriptor *io_spi_master;
|
|
|
|
/* DATA transfer/reception completion flags */
|
|
volatile uint8_t spi_slave_tx_complete = 0;
|
|
volatile uint8_t spi_slave_rx_complete = 0;
|
|
volatile uint8_t spi_master_tx_complete = 0;
|
|
volatile uint8_t spi_master_rx_complete = 0;
|
|
volatile uint8_t cs_pulled_high = 0;
|
|
volatile uint8_t received_data_len = 0;
|
|
|
|
static uint8_t rx_buffer[BUFFER_LEN] = {0};
|
|
static uint8_t tx_buffer[BUFFER_LEN] = "Hello World!";
|
|
|
|
/* DMA Transfer complete callback for SPI master TX */
|
|
static void spi_master_tx_complete_cb(struct _dma_resource *resource)
|
|
{
|
|
/* Transfer completed */
|
|
delay_us(CONF_DELAY_US);
|
|
gpio_set_pin_level(SPI_CS, true);
|
|
spi_master_tx_complete = true;
|
|
}
|
|
|
|
/* DMA Transfer complete callback for SPI master RX */
|
|
static void spi_master_rx_complete_cb(struct _dma_resource *resource)
|
|
{
|
|
/* Transfer completed */
|
|
gpio_set_pin_level(SPI_CS, true);
|
|
spi_master_rx_complete = true;
|
|
}
|
|
|
|
/* Start SPI master data transfer */
|
|
void spi_master_tx(uint8_t *buffer, uint8_t length)
|
|
{
|
|
spi_m_dma_enable(&SPI_0);
|
|
gpio_set_pin_level(SPI_CS, false);
|
|
io_write(io_spi_master, buffer, length);
|
|
}
|
|
|
|
/* Start SPI master data Reception from Slave */
|
|
void spi_master_rx(uint8_t *buffer, uint8_t length)
|
|
{
|
|
spi_m_dma_enable(&SPI_0);
|
|
gpio_set_pin_level(SPI_CS, false);
|
|
io_read(io_spi_master, buffer, length);
|
|
}
|
|
|
|
/* SPI master IO and Callback Initialization */
|
|
void spi_master_init(void)
|
|
{
|
|
spi_m_dma_get_io_descriptor(&SPI_0, &io_spi_master);
|
|
spi_m_dma_register_callback(&SPI_0, SPI_M_DMA_CB_TX_DONE, spi_master_tx_complete_cb);
|
|
spi_m_dma_register_callback(&SPI_0, SPI_M_DMA_CB_RX_DONE, spi_master_rx_complete_cb);
|
|
}
|
|
|
|
/* SPI Slave Chip Select low to high change callback */
|
|
static void slave_select_high(void)
|
|
{
|
|
received_data_len = (_descriptor_section[CONF_SERCOM_6_RECEIVE_DMA_CHANNEL].BTCNT.reg
|
|
- _write_back_section[CONF_SERCOM_6_RECEIVE_DMA_CHANNEL].BTCNT.reg);
|
|
cs_pulled_high = true;
|
|
}
|
|
|
|
/* DMA Transfer complete callback for SPI Slave RX */
|
|
static void spi_slave_rx_complete_cb(struct _dma_resource *const resource)
|
|
{
|
|
spi_slave_rx_complete = true;
|
|
}
|
|
|
|
/* DMA Transfer complete callback for SPI Slave TX */
|
|
static void spi_slave_tx_complete_cb(struct _dma_resource *const resource)
|
|
{
|
|
spi_slave_tx_complete = true;
|
|
}
|
|
|
|
/* Register SPI Slave DMA channel callbacks */
|
|
void register_dma_spi_slave_callback(uint16_t channel, void *cb)
|
|
{
|
|
struct _dma_resource *resource_rx;
|
|
_dma_get_channel_resource(&resource_rx, channel);
|
|
resource_rx->dma_cb.transfer_done = cb;
|
|
}
|
|
|
|
/* Enable SPI slave slave select interrupt */
|
|
void spi_s_sync_enable_ss_detect(void *hw, bool state)
|
|
{
|
|
NVIC_DisableIRQ((IRQn_Type)SERCOM6_1_IRQn);
|
|
NVIC_ClearPendingIRQ((IRQn_Type)SERCOM6_1_IRQn);
|
|
NVIC_EnableIRQ((IRQn_Type)SERCOM6_1_IRQn);
|
|
if (state) {
|
|
hri_sercomspi_set_INTEN_TXC_bit(hw);
|
|
} else {
|
|
hri_sercomspi_clear_INTEN_TXC_bit(hw);
|
|
}
|
|
}
|
|
|
|
/* slave slave interrupt handler */
|
|
void SERCOM6_1_Handler()
|
|
{
|
|
hri_sercomspi_clear_INTEN_TXC_bit((SercomSpi *)(SPI_1.dev.prvt));
|
|
slave_select_high();
|
|
}
|
|
|
|
/* SERCOM SPI Slave configuration */
|
|
void spi_slave_init()
|
|
{
|
|
_dma_set_source_address(CONF_SERCOM_6_RECEIVE_DMA_CHANNEL,
|
|
(uint32_t *)&(((SercomSpi *)(SPI_1.dev.prvt))->DATA.reg));
|
|
_dma_set_destination_address(CONF_SERCOM_6_TRANSMIT_DMA_CHANNEL,
|
|
(uint32_t *)&(((SercomSpi *)(SPI_1.dev.prvt))->DATA.reg));
|
|
|
|
/* callback */
|
|
register_dma_spi_slave_callback(CONF_SERCOM_6_TRANSMIT_DMA_CHANNEL, spi_slave_tx_complete_cb);
|
|
register_dma_spi_slave_callback(CONF_SERCOM_6_RECEIVE_DMA_CHANNEL, spi_slave_rx_complete_cb);
|
|
|
|
/* Enable DMA transfer complete interrupt */
|
|
_dma_set_irq_state(CONF_SERCOM_6_RECEIVE_DMA_CHANNEL, DMA_TRANSFER_COMPLETE_CB, true);
|
|
_dma_set_irq_state(CONF_SERCOM_6_TRANSMIT_DMA_CHANNEL, DMA_TRANSFER_COMPLETE_CB, true);
|
|
|
|
spi_s_sync_enable_ss_detect((SercomSpi *)(SPI_1.dev.prvt), true);
|
|
}
|
|
|
|
/* Start SPI slave data transfer */
|
|
void spi_slave_tx(uint8_t *buffer, uint8_t length)
|
|
{
|
|
spi_s_sync_enable(&SPI_1);
|
|
_dma_set_source_address(CONF_SERCOM_6_TRANSMIT_DMA_CHANNEL, (uint32_t *)buffer);
|
|
_dma_srcinc_enable(CONF_SERCOM_6_TRANSMIT_DMA_CHANNEL, true);
|
|
_dma_set_data_amount(CONF_SERCOM_6_TRANSMIT_DMA_CHANNEL, (uint32_t)length);
|
|
_dma_enable_transaction(CONF_SERCOM_6_TRANSMIT_DMA_CHANNEL, false);
|
|
}
|
|
|
|
/* Start SPI slave data reception */
|
|
void spi_slave_rx(uint8_t *buffer, uint8_t length)
|
|
{
|
|
spi_s_sync_enable(&SPI_1);
|
|
_dma_set_destination_address(CONF_SERCOM_6_RECEIVE_DMA_CHANNEL, (uint32_t *)buffer);
|
|
_dma_set_data_amount(CONF_SERCOM_6_RECEIVE_DMA_CHANNEL, (uint32_t)length);
|
|
_dma_enable_transaction(CONF_SERCOM_6_RECEIVE_DMA_CHANNEL, false);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
/* Initializes MCU, drivers and middleware */
|
|
atmel_start_init();
|
|
/* Initialize SPI master IO and Callback */
|
|
spi_master_init();
|
|
/* SPI Slave DMA and Callback configuration */
|
|
spi_slave_init();
|
|
/* Start SPI Slave data reception using DMA */
|
|
spi_slave_rx(rx_buffer, BUFFER_LEN);
|
|
/* Start SPI Master data transfer using DMA */
|
|
spi_master_tx(tx_buffer, BUFFER_LEN);
|
|
|
|
while (1) {
|
|
/* Check for SPI Slave is received data from SPI Master */
|
|
if (spi_slave_rx_complete) {
|
|
spi_slave_rx_complete = false;
|
|
printf("Slave Received DATA Length = %d\n\rSlave Received DATA = ", received_data_len);
|
|
/* Print Received data by SPI Slave from SPI Master on Console */
|
|
for (int i = 0; i < BUFFER_LEN; i++) {
|
|
printf("%c", rx_buffer[i]);
|
|
}
|
|
printf("\n\r");
|
|
|
|
/* Start SPI Slave data transfer using DMA */
|
|
spi_slave_tx(rx_buffer, BUFFER_LEN);
|
|
|
|
/* Start SPI Master data reception using DMA */
|
|
spi_master_rx(tx_buffer, BUFFER_LEN);
|
|
}
|
|
|
|
/* Check for SPI Master is received data from SPI Slave */
|
|
if (spi_master_rx_complete) {
|
|
spi_master_rx_complete = false;
|
|
printf("Master Received DATA Length = %d\n\rMaster Received DATA = ", received_data_len);
|
|
/* Print Received data by SPI Master from SPI Slave on Console */
|
|
for (int i = 0; i < BUFFER_LEN; i++) {
|
|
printf("%c", tx_buffer[i]);
|
|
}
|
|
printf("\n\r");
|
|
//delay_ms(500);
|
|
//spi_master_tx(tx_buffer, BUFFER_LEN);
|
|
}
|
|
delay_ms(500);
|
|
spi_slave_rx(rx_buffer, BUFFER_LEN);
|
|
spi_master_tx(tx_buffer, BUFFER_LEN);
|
|
}
|
|
|
|
|
|
}
|