Files
zTC1/mico-os/platform/MCU/ATSAMG55/peripherals/platform_spi.c
2025-03-11 15:54:45 +08:00

239 lines
7.9 KiB
C

/**
******************************************************************************
* @file platform_spi.c
* @author William Xu
* @version V1.0.0
* @date 05-May-2014
* @brief This file provide SPI driver functions.
******************************************************************************
* UNPUBLISHED PROPRIETARY SOURCE CODE
* Copyright (c) 2016 MXCHIP Inc.
*
* The contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of MXCHIP Corporation.
******************************************************************************
*/
#include "platform.h"
#include "platform_peripheral.h"
/******************************************************
* Constants
******************************************************/
/******************************************************
* Enumerations
******************************************************/
/******************************************************
* Type Definitions
******************************************************/
/******************************************************
* Structures
******************************************************/
/******************************************************
* Variables Definitions
******************************************************/
/******************************************************
* Function Declarations
******************************************************/
/******************************************************
* Function Definitions
******************************************************/
OSStatus platform_spi_init( platform_spi_driver_t* driver, const platform_spi_t* peripheral, const platform_spi_config_t* config )
{
pdc_packet_t pdc_spi_packet;
Pdc* spi_pdc;
OSStatus err = kNoErr;
platform_mcu_powersave_disable( );
require_action_quiet( ( driver != NULL ) && ( peripheral != NULL ) && ( config != NULL ), exit, err = kParamErr);
driver->peripheral = (platform_spi_t *)peripheral;
spi_pdc = spi_get_pdc_base( peripheral->port );
/* Setup chip select pin */
platform_gpio_init( config->chip_select, OUTPUT_PUSH_PULL );
platform_gpio_output_high( config->chip_select );
/* Setup other pins */
platform_gpio_peripheral_pin_init( peripheral->mosi_pin, ( peripheral->mosi_pin_mux_mode | IOPORT_MODE_PULLUP ) );
platform_gpio_peripheral_pin_init( peripheral->miso_pin, ( peripheral->miso_pin_mux_mode | IOPORT_MODE_PULLUP ) );
platform_gpio_peripheral_pin_init( peripheral->clock_pin, ( peripheral->clock_pin_mux_mode | IOPORT_MODE_PULLUP ) );
/* Enable the peripheral and set SPI mode. */
if( pmc_is_periph_clk_enabled( driver->peripheral->peripheral_id ) == 0 ){
flexcom_enable( driver->peripheral->flexcom_base );
}
flexcom_set_opmode( driver->peripheral->flexcom_base, FLEXCOM_SPI );
/* Init pdc, and clear RX TX. */
pdc_spi_packet.ul_addr = 0;
pdc_spi_packet.ul_size = 1;
pdc_tx_init( spi_pdc, &pdc_spi_packet, NULL );
pdc_rx_init( spi_pdc, &pdc_spi_packet, NULL );
/* Configure an SPI peripheral. */
spi_disable( peripheral->port );
spi_reset( peripheral->port );
spi_set_lastxfer( peripheral->port );
spi_set_master_mode( peripheral->port );
spi_disable_mode_fault_detect( peripheral->port );
spi_set_peripheral_chip_select_value( peripheral->port, 0 );
spi_set_clock_polarity( peripheral->port, 0, ( ( config->mode & SPI_CLOCK_IDLE_HIGH ) ? (1) : (0) ) );
spi_set_clock_phase( peripheral->port, 0, ( ( config->mode & SPI_CLOCK_FALLING_EDGE ) ? (1) : (0) ) );
spi_set_bits_per_transfer( peripheral->port, 0, SPI_CSR_BITS_8_BIT );
spi_set_baudrate_div( peripheral->port, 0, (uint8_t)( sysclk_get_cpu_hz() / config->speed ) );
spi_set_transfer_delay( peripheral->port, 0, 0, 0 );
spi_enable( peripheral->port );
pdc_disable_transfer( spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS );
exit:
platform_mcu_powersave_enable( );
return err;
}
OSStatus platform_spi_deinit( platform_spi_driver_t* driver )
{
/* Disable the RX and TX PDC transfer requests */
if( pmc_is_periph_clk_enabled( driver->peripheral->peripheral_id ) == 1 ){
flexcom_disable( driver->peripheral->flexcom_base );
}
spi_disable( driver->peripheral->port );
spi_reset( driver->peripheral->port );
return kNoErr;
}
OSStatus samg5x_spi_transfer_internal( const platform_spi_t* spi, const uint8_t* data_out, uint8_t* data_in, uint32_t data_length )
{
Pdc* spi_pdc = spi_get_pdc_base( spi->port );
pdc_packet_t pdc_spi_packet;
uint8_t junk3;
uint16_t junk2;
/* Send and read */
if( data_in != NULL && data_out != NULL )
{
pdc_spi_packet.ul_addr = (uint32_t)data_in;
pdc_spi_packet.ul_size = (uint32_t)data_length;
pdc_rx_init( spi_pdc, &pdc_spi_packet, NULL );
pdc_spi_packet.ul_addr = (uint32_t)data_out;
pdc_spi_packet.ul_size = (uint32_t)data_length;
pdc_tx_init( spi_pdc, &pdc_spi_packet, NULL );
/* Enable the RX and TX PDC transfer requests */
pdc_enable_transfer( spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN );
/* Waiting transfer done*/
while ( ( spi_read_status( spi->port ) & SPI_SR_RXBUFF ) == 0 )
{
}
/* Disable the RX and TX PDC transfer requests */
pdc_disable_transfer(spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
pdc_spi_packet.ul_addr = 0;
pdc_spi_packet.ul_size = 1;
pdc_rx_init( spi_pdc, &pdc_spi_packet, NULL );
pdc_tx_init( spi_pdc, &pdc_spi_packet, NULL );
}
/* Send Only */
else if( data_in == NULL && data_out != NULL)
{
pdc_spi_packet.ul_addr = (uint32_t)data_out;
pdc_spi_packet.ul_size = (uint32_t)data_length;
pdc_tx_init( spi_pdc, &pdc_spi_packet, NULL );
/* Enable the TX PDC transfer requests */
pdc_enable_transfer( spi_pdc, PERIPH_PTCR_TXTEN );
/* Waiting transfer done*/
while ( ( spi_read_status( spi->port ) & SPI_SR_ENDTX ) == 0 )
{
}
/* Disable the RX and TX PDC transfer requests */
pdc_disable_transfer(spi_pdc, PERIPH_PTCR_TXTDIS);
pdc_spi_packet.ul_addr = 0;
pdc_spi_packet.ul_size = 1;
pdc_tx_init( spi_pdc, &pdc_spi_packet, NULL );
spi_read( spi->port, &junk2, &junk3);
}
/* Read Only */
else if( data_in != NULL && data_out == NULL)
{
pdc_spi_packet.ul_addr = (uint32_t)data_in;
pdc_spi_packet.ul_size = (uint32_t)data_length;
pdc_rx_init( spi_pdc, &pdc_spi_packet, NULL );
pdc_spi_packet.ul_addr = (uint32_t)data_in;
pdc_spi_packet.ul_size = (uint32_t)data_length;
pdc_tx_init( spi_pdc, &pdc_spi_packet, NULL );
/* Enable the RX and TX PDC transfer requests */
pdc_enable_transfer( spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN );
/* Waiting transfer done*/
while ( ( spi_read_status( spi->port ) & SPI_SR_RXBUFF ) == 0 )
{
}
/* Disable the RX and TX PDC transfer requests */
pdc_disable_transfer(spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
pdc_spi_packet.ul_addr = 0;
pdc_spi_packet.ul_size = 1;
pdc_rx_init( spi_pdc, &pdc_spi_packet, NULL );
pdc_tx_init( spi_pdc, &pdc_spi_packet, NULL );
}
return kNoErr;
}
OSStatus platform_spi_transfer( platform_spi_driver_t* driver, const platform_spi_config_t* config, const platform_spi_message_segment_t* segments, uint16_t number_of_segments )
{
int i = 0;
OSStatus result;
platform_mcu_powersave_disable( );
platform_gpio_output_low( config->chip_select );
for ( i = 0; i < number_of_segments; i++ )
{
if( segments[i].length == 0)
continue;
result = samg5x_spi_transfer_internal( driver->peripheral, segments[i].tx_buffer, segments[i].rx_buffer, segments[i].length );
if ( result != kNoErr )
{
return result;
}
}
platform_gpio_output_high( config->chip_select );
platform_mcu_powersave_enable( );
return kNoErr;
}