/** * \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 Microchip Support */ #include #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); } }