Configuración de SPI con sam4s16c

3

Comencé a ser programador de software y tengo experiencia profesional con grandes proyectos de software en c ++ y QT. Ahora cambié de compañía y también tengo que escribir un código de hardware de bajo nivel y tengo algunos problemas iniciales, jugando con los tonos de las hojas de datos. Soy nuevo en la programación de hardware en general y no sé mucho sobre herramientas o cómo puedo ayudarme a mí mismo.

Mi plan es comenzar la comunicación con un Sam4s16c (en un SAM4SXplained board ) a a L6470 motor a través de SPI. Mi problema es que la configuración de SPI me da dolor de cabeza y no funcionará. Al medir el CS / SS (pin31A), un osciloscopio solo mostrará alto voltaje (~ 3,2 V) pero no un reloj válido (debería ver un "arriba y abajo" aquí, o no?).

No estoy seguro de cuál es un buen valor para el divisor de velocidad en baudios (y qué significa en general) Después de mucho leer, escuché que tengo que "configurar" los pines correctamente, probé esto con estas líneas

gpio_configure_pin(SPI_NPCS1_PA31_GPIO, SPI_NPCS1_PA31_FLAGS);
gpio_set_pin_high(SPI_NPCS1_PA31_GPIO);

Mi código hasta ahora.

#include "asf.h"
#include "stdio_serial.h"
#include "conf_board.h"
#include "conf_clock.h"
#include "conf_spi_example.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Chip select. */
#define SPI_CHIP_SEL 0
#define SPI_CHIP_PCS spi_get_pcs(SPI_CHIP_SEL)

/* Clock polarity. */
#define SPI_CLK_POLARITY 1

/* Clock phase. */
#define SPI_CLK_PHASE 1

/* 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;


volatile uint32_t g_ul_ms_ticks = 0;
void SysTick_Handler(void)
{
    g_ul_ms_ticks++;
}
static void mdelay(uint32_t ul_dly_ticks)
{
    uint32_t ul_cur_ticks;

    ul_cur_ticks = g_ul_ms_ticks;
    while ((g_ul_ms_ticks - ul_cur_ticks) < ul_dly_ticks);
}


/**
 * \brief Initialize SPI as master.
 */
static void spi_master_initialize(void)
{
    //Assign I/O lines to peripheral
    #define SPI_MISO_IOPIN  IOPORT_CREATE_PIN(PIOA, PIO_PA12_IDX)
    #define SPI_MOSI_IOPIN  IOPORT_CREATE_PIN(PIOA, PIO_PA13_IDX)
    #define SPI_SPCK_IOPIN  IOPORT_CREATE_PIN(PIOA, PIO_PA14_IDX)
    #define SPI_NPCS1_IOPIN  IOPORT_CREATE_PIN(PIOA, PIO_PA31_IDX)

    ioport_set_pin_mode(SPI_MISO_IOPIN, PIO_PERIPH_A);
    ioport_disable_pin(SPI_MISO_IOPIN);
    ioport_set_pin_mode(SPI_MOSI_IOPIN, PIO_PERIPH_A);
    ioport_disable_pin(SPI_MOSI_IOPIN);
    ioport_set_pin_mode(SPI_SPCK_IOPIN, PIO_PERIPH_A);
    ioport_disable_pin(SPI_SPCK_IOPIN);
    ioport_set_pin_mode(SPI_NPCS1_IOPIN, PIO_PERIPH_A);
    ioport_disable_pin(SPI_NPCS1_IOPIN);

    /* Configure an SPI peripheral. */
    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_get_pcs(SPI_CHIP_PCS));
    spi_set_fixed_peripheral_select(SPI_MASTER_BASE);
    spi_set_delay_between_chip_select(SPI_MASTER_BASE, 0);

    // Set the Chip Select register
    spi_set_transfer_delay(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_DLYBS, SPI_DLYBCT);

    int16_t baudrate = spi_calc_baudrate_div(96000, sysclk_get_cpu_hz());
    spi_set_baudrate_div(SPI_MASTER_BASE, SPI_CHIP_SEL, 8); //sysclk_get_cpu_hz() / gs_ul_spi_clock);
    spi_set_bits_per_transfer(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_CSR_BITS_8_BIT);
    //spi_configure_cs_behavior(SPI_MASTER_BASE, SPI_CHIP_SEL, 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_enable(SPI_MASTER_BASE);

    mdelay(100);
}

static void spi_master_write(uint16_t value)
{
    spi_write(SPI_MASTER_BASE, value, SPI_CHIP_SEL, 0);
    while ((spi_read_status(SPI) & SPI_SR_RDRF) == 0);/* Wait transfer done. */
}

static spi_status_t spi_master_read(uint16_t* data)
{
    uint8_t uc_pcs;

    spi_status_t returnValue = spi_read(SPI_MASTER_BASE, data, &uc_pcs);
    return returnValue;
}

static void ledHello(void)
{
    for (int i=0; i < 6; ++i)
    {
        LED_Toggle(LED0_GPIO);
        LED_Toggle(LED1_GPIO);
        mdelay(150);
    }
    mdelay(150);

    for (int i=0; i < 5; ++i)
    {
        LED_Toggle(LED0_GPIO);
        mdelay(150);
    }

    for (int i=0; i < 5; ++i)
    {
        LED_Toggle(LED1_GPIO);
        mdelay(150);
    }
    // Both LEDs stay permanent on
}

int main(void)
{
    board_init();
    sysclk_init();

    NVIC_DisableIRQ(SPI_IRQn);
    NVIC_ClearPendingIRQ(SPI_IRQn);
    NVIC_SetPriority(SPI_IRQn, 0);
    NVIC_EnableIRQ(SPI_IRQn);

    // [main_step_systick_init]
    if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) {
        // Systick configuration error
        while (1);
    }

    ledHello(); // Code here toggles leds on board

    /* Configure SPI as master, set up SPI clock. */
    spi_master_initialize();

    // activate the SPI of the micro controller of the L6470 via SPI
    spi_master_write(0x18); // SetParam(Config)
    spi_master_write(0x16);
    spi_master_write(0x10);

    mdelay(100);
    while (1) {
        spi_master_write(0x38); // GetParam(Config)
        static uint16_t data;
        spi_master_read(data);
        spi_master_read(data);
    }
}

#ifdef __cplusplus
}
#endif

En este momento, trato de configurar el reloj / salida spi correctamente. ¿Me perdí algo?

    
pregunta norca

1 respuesta

2

Te estás perdiendo la configuración de GPIO. NO DEBE asignar la función GPIO, pero debe indicar al pin qué función alternativa tiene realmente. Esto será algo a lo largo de las líneas:

#define SPI_SO_PIN                      PIN_PC28B_SPI_MISO  
#define SPI_SO_MUX                      MUX_PC28B_SPI_MISO  
#define SPI_SI_PIN                      PIN_PC29B_SPI_MOSI  
#define SPI_SI_MUX                      MUX_PC29B_SPI_MOSI  
#define SPI_SCK_PIN                     PIN_PC30B_SPI_SCK   
#define SPI_SCK_MUX                     MUX_PC30B_SPI_SCK   
#define SPI_CS0_PIN                     PIN_PC31B_SPI_NPCS0 
#define SPI_CS0_MUX                     MUX_PC31B_SPI_NPCS0 

#define ioport_set_pin_peripheral_mode(pin, mode) \
do {\
    ioport_set_pin_mode(pin, mode);\
    ioport_disable_pin(pin);\
} while (0)

ioport_set_pin_peripheral_mode(SPI_SCK_PIN, SPI_SCK_MUX);
ioport_set_pin_peripheral_mode(SPI_SO_PIN, SPI_SO_MUX);
ioport_set_pin_peripheral_mode(SPI_SI_PIN, SPI_SI_MUX);
ioport_set_pin_peripheral_mode(SPI_CS0_PIN, SPI_CS0_MUX);

Atmel tiene un buen repositorio de ejemplos. Inicie Atmel Studio, seleccione un nuevo proyecto de ejemplo, seleccione su controlador o placa y cargue algo relacionado con el componente que está implementando (SPI en su caso). Luego siga "principal" hasta que llegue al punto en el que está interesado. A partir de ahí, por lo general es sencillo.

Si un pin no se mueve por alguna razón, lo mejor es que tienes una configuración incorrecta de GPIO (o configuración de ping alternativa).

Parece que el SAM4S es un poco diferente del SAM4L. Si observa el ejemplo de SPI suministrado desde ASF, verá la secuencia de inicio (función board_init () en SPI_EXAMPLE1 \ src \ ASF \ sam \ boards \ sam4s_ek \ init.c) como:

/* Configure an SPI peripheral. */
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_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_peripheral_hz()/ gs_ul_spi_clock));
spi_set_transfer_delay(SPI_MASTER_BASE, SPI_CHIP_SEL, SPI_DLYBS, SPI_DLYBCT);
spi_enable(SPI_MASTER_BASE);

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_NPCS0_GPIO, SPI_NPCS0_FLAGS);

Para hablar realmente con un dispositivo, deberá seleccionar ese dispositivo (esto es lo que hace spi_set_peripheral_chip_select_value, también incluye lógica si tiene un DEMUX incorporado, por eso usa la macro spi_get_pcs). Como SPI_CHIP_SEL es 0, hablará con cualquier dispositivo que esté conectado a CS0. Si desea hablar con un dispositivo en una línea de selección de chip diferente, deberá modificar estos valores y la configuración de GPIO en consecuencia.

Tu primera tarea es reducir la línea de selección de chips. A menos que esto se haga, nunca recibirás datos del esclavo porque piensa que no estás hablando con él sino con algún otro dispositivo en el mismo bus SPI.

    
respondido por el Tom L.

Lea otras preguntas en las etiquetas