¿Cómo puedo configurar SPI usando Atmel Studio y el código C para el procesador ARM?

1

Estoy intentando programar el chip SAM3x8E en el Arduino Due a través de Atmel Studio. Me gustaría poder controlar una resistencia digital a través de la interfaz SPI con el chip SAM3. Estoy ejecutando Atmel Studio 6.2. No tengo ningún problema para que las cosas funcionen en el IDE de Arduino, pero realmente quiero averiguar cómo programar esto de la "manera difícil" en Atmel. Puedo programar exitosamente el chip en Atmel Studio, usando un archivo por lotes que carga bosssa.exe.

Aquí está mi código IDE de Arduino de TRABAJO:

Código:

// inslude the SPI library:
#include <SPI.h>


// set pin 10 as the slave select for the digital pot:
const int slaveSelectPin = 13;

void setup() {
  // initialize SPI:
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
 // SPI.setClockDivider(slaveSelectPin, 8);
  SPI.setBitOrder(LSBFIRST);
  pinMode (slaveSelectPin, OUTPUT);
}

void loop() {

  // Raise the volume from off to loud

  // Increase brightness of LED
  for (int i = 63; i>=0; i--) {
    digitalPotWrite(i, i);

    if(i>20)
    delay(10);
    else
    delay(100);
  }

      digitalPotWrite(0, 0);
       // delay(500);


  // Decrease brightness of LED
  for (int i = 0; i <= 63; i++) {
    digitalPotWrite(i, i);     

    if(i>20)
    delay(10);
    else
    delay(100);
  }
}

void digitalPotWrite(int left, int right) {
  // take the SS pin low to select the chip:
  digitalWrite(slaveSelectPin, HIGH);
  //  send in the address and value via SPI:
  SPI.transfer(left);
  SPI.transfer(right);
  // take the SS pin high to de-select the chip:
  digitalWrite(slaveSelectPin, LOW);
}

Ahora (tristemente), este es mi código Atmel:

Código:

#include <asf.h>
#include "spi_master.h"


int main (void)
{
   /* Initialize the SAM system. */
   sysclk_init();
   board_init();

}

Como puede ver, no tengo la menor idea de cómo configurar la interfaz SPI en Atmel studio. He visto un código de ejemplo como el "SPI_EXAMPLE1" incorporado, pero no lo entiendo. ¿Alguien puede ayudarme a entender cómo se inicializa el SPI? ¿Cómo puedo saber qué pines usar en el código de inicialización?

    
pregunta John August

2 respuestas

2

Tienes dos opciones aquí. Puede configurar manualmente los registros de configuración directamente para el periférico SPI, o puede usar el "Atmel Software Framework" que resume muchos de los detalles en una API de nivel superior. En cualquier caso, tendrá que lidiar con muchas cosas que el entorno de Arduino maneja por usted.

Necesitará configurar el reloj del procesador, lo que significa seleccionar una fuente (por lo general, tiene la opción de alta velocidad interna, baja velocidad interna, cristal externo de alta frecuencia, cristal externo de baja frecuencia o reloj externo) y una combinación de multiplicadores / divisores que derivan la frecuencia de reloj central deseada. Luego, debe asegurarse de que el periférico SPI y los módulos GPIO reciban una señal de reloj (de manera predeterminada, los relojes no se enrutan a ningún periférico para ahorrar energía) y que la señal de reloj se divide a una velocidad adecuada (la hoja de datos de la MCU especifique el tiempo mínimo / máximo, como lo hará la hoja de datos de su IC externo, y deberá asegurarse de que cumple con los requisitos de ambos).

Deberá configurar correctamente los pines GPIO para permitir que el periférico SPI los controle. Muchas MCU de esta clase tendrán varias unidades SPI, y la hoja de datos especificará qué pines pueden ser utilizados por cada unidad. La mayoría de los pines tendrán muchos periféricos que se pueden seleccionar, por lo que deberá configurar el multiplexor de pines para seleccionar la unidad SPI adecuada. También necesitarás establecer la dirección del pasador y las subidas / bajadas según sea necesario.

Finalmente, deberá configurar el periférico SPI. Esto incluirá la configuración de la velocidad del reloj, qué bordes de reloj usar, maestro / esclavo, enrutamiento de patillas y muchas otras opciones que se detallarán en la hoja de datos.

Si estás empezando, ASF es el camino a seguir. Hay ejemplos en la documentación de ASF vinculados en comentarios anteriores que deberían ayudarlo, y si los examina detenidamente, debería ver que las aplicaciones de ejemplo hacen todas las cosas que he descrito anteriormente. Sin embargo, la documentación de ASF hace un trabajo excepcionalmente deficiente al explicar realmente lo que está pasando y por qué, por lo que deberá estudiar detenidamente las secciones de la hoja de datos de MCU sobre reloj, administración de energía, GPIO y SPI para descubrir realmente lo que está haciendo. . Desafortunadamente, la hoja de datos también hace un mal trabajo al explicar cómo se deben usar los periféricos, por lo que será necesario leer entre líneas. Como regla general, las API y la documentación del proveedor para MCU de ARM (no solo las SAM de Atmel) no son muy buenas, por lo que se requerirá mucha lectura y experimentación. Utilice la función "Ir a la implementación" de Atmel Studio con el botón derecho del mouse para aprender más acerca de lo que ASF está haciendo bajo el capó. Volver a consultar las descripciones de la hoja de datos de las diversas funciones de los registros de hardware ayudará.

Así que todo eso es una respuesta muy general: su solución específica dependerá de la configuración de hardware particular que tenga, por lo que tendrá que mirar los esquemas de Arduino Due para descubrir qué pines necesitará usar para SPI y qué ajustes de reloj son apropiados. La MCU comenzará a ejecutarse desde un oscilador interno de manera predeterminada, por lo que le sugiero que comience simplemente haciendo funcionar el GPIO. Simplemente parpadee un LED para asegurarse de que tiene el bloqueo del GPIO, luego comience a trabajar con el módulo SPI .

Por encima de todo, ¡recuerda que la hoja de datos es tu amigo!

    
respondido por el ajb
2

Aunque, los desarrolladores con experiencia dicen que los principiantes deben ir con ASF (lo que en realidad es cierto), no significa que pueda lograr con menos esfuerzo la misma cosa. Solo necesitas diferentes tipos de esfuerzo. (consulte: enlace )

De todos modos, para responder a la pregunta: He implementado SPI con ASF en modo maestro, modo SPI 0 en SAM4S16C. Echa un vistazo a esta publicación para obtener más información: enlace Aquí proporciono las partes esenciales.

Agregue los siguientes servicios / controladores a su proyecto con el Asistente de ASF:

  • GPIO
  • IOPORT
  • SPI
  • gestión de interrupciones
  • Control del reloj del sistema

En su archivo init.c, inicialice los controladores y los servicios.

#include <asf.h>
#include <board.h>
#include <conf_board.h>

void board_init(void)
{

 WDT->WDT_MR = WDT_MR_WDDIS; //switch off watchdog

 sysclk_init();
 ioport_init();
 irq_initialize_vectors();
 cpu_irq_enable();

 //Set Led Pin directions
 ioport_set_pin_dir(LED0_PIN,IOPORT_DIR_OUTPUT);
 ioport_set_pin_dir(LED1_PIN,IOPORT_DIR_OUTPUT);
}

SPI init: Este método de inicio configurará SPI en modo maestro, el modo SPI será el modo SPI 0, con una frecuencia de reloj de aproximadamente 1MHz.

#define SPI_ID            ID_SPI
#define SPI_MASTER_BASE     SPI
#define SPI_MISO_GPIO  (PIO_PA12_IDX)
#define SPI_MISO_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define SPI_MOSI_GPIO  (PIO_PA13_IDX)
#define SPI_MOSI_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define SPI_SPCK_GPIO  (PIO_PA14_IDX)
#define SPI_SPCK_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define SPI_NPCS0_GPIO            (PIO_PA11_IDX)
#define SPI_NPCS1_GPIO            (PIO_PA31_IDX)
#define SPI_NPCS1_FLAGS           (PIO_PERIPH_A | PIO_DEFAULT)
#define SPI_CHIP_SEL 1    //Use SPI Chip Select 1 (SPI_NPCS1_GPIO) for CS
#define SPI_CHIP_PCS spi_get_pcs(SPI_CHIP_SEL)

/* Clock polarity. */
#define SPI_CLK_POLARITY 0

/* Clock phase. */
#define SPI_CLK_PHASE 0

/* Delay before SPCK. */
//#define SPI_DLYBS 0x40
#define SPI_DLYBS 0xFF

/* Delay between consecutive transfers. */
#define SPI_DLYBCT 0x10
/* SPI clock setting (Hz). */
static uint32_t gs_ul_spi_clock = 1000000;

//Paramteres:
//  data: data to be sent
//  last_byte: either 0 or 1. 
//   0-There are following bytes to be sent. The following bytes and the current byte composes one data-unit, CS should be kept low after sending out the current byte
//   1-Last byte of a data unit. CS will be set to HIGH when the current byte has been sent out.
void spi_tx(uint8_t data,uint8_t last_byte)
{
 spi_write(SPI,data,SPI_CHIP_SEL,last_byte);
 while ((spi_read_status(SPI) & SPI_SR_RDRF) == 0);/* Wait transfer done. */
}

uint8_t spi_rx(void)
{
 uint8_t tmp;
 spi_read (SPI,&tmp,SPI_CHIP_SEL);
 return tmp;
}

void spi_init(void)
{
        //Assign I/O lines to peripheral
 gpio_configure_pin(SPI_MISO_GPIO, SPI_MISO_FLAGS);
 gpio_configure_pin(SPI_MOSI_GPIO, SPI_MOSI_FLAGS);
 gpio_configure_pin(SPI_SPCK_GPIO, SPI_SPCK_FLAGS);
 gpio_configure_pin(SPI_NPCS1_GPIO, SPI_NPCS1_FLAGS);

 spi_enable_clock(SPI_MASTER_BASE);
 spi_disable(SPI_MASTER_BASE);
 spi_reset(SPI_MASTER_BASE);
 spi_set_lastxfer(SPI_MASTER_BASE);
 spi_set_master_mode(SPI_MASTER_BASE);
 spi_disable_mode_fault_detect(SPI_MASTER_BASE);
 spi_set_peripheral_chip_select_value(SPI_MASTER_BASE, SPI_CHIP_PCS);
 spi_configure_cs_behavior(SPI, 1, SPI_CS_RISE_NO_TX);
 spi_set_clock_polarity(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_CLK_POLARITY);
 spi_set_clock_phase(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_CLK_PHASE);
 spi_set_bits_per_transfer(SPI_MASTER_BASE, SPI_CHIP_SEL,
 SPI_CSR_BITS_8_BIT);
 spi_set_baudrate_div(SPI_MASTER_BASE, SPI_CHIP_SEL,(sysclk_get_cpu_hz() / gs_ul_spi_clock));
 spi_set_transfer_delay(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_DLYBS,SPI_DLYBCT);
 spi_enable(SPI_MASTER_BASE);
}
    
respondido por el bakcsa83

Lea otras preguntas en las etiquetas