Ich habe als Programmierer für Software angefangen und habe einen professionellen Hintergrund mit großen Softwareprojekten in C++ und QT. Jetzt habe ich die Firma gewechselt und muss auch etwas Low-Level-Hardwarecode schreiben, und ich habe einige Startprobleme, indem ich mit Tönen von Datenblättern herumgespielt habe. Ich bin neu in der Hardwareprogrammierung im Allgemeinen und weiß nicht viel über Tools oder wie ich mir selbst helfen kann.
Mein Plan ist es, die Kommunikation mit einem Sam4s16c (auf einem SAM4SXplained-Board ) mit einem L6470- Motor über SPI zu starten. Mein Problem ist, dass das SPI-Setup mir Kopfschmerzen bereitet und nicht funktioniert. Beim Messen von CS/SS (Pin31A) zeigt ein Oszilloskop nur eine hohe Spannung (~3,2 V), aber keinen gültigen Takt (ich sollte hier ein "Auf und Ab" sehen, oder nicht?).
Ich bin mir nicht sicher, was ein guter Wert für den Baudratenteiler ist (und was er im Allgemeinen bedeutet). Nach viel Lesen habe ich gehört, dass ich die Pins richtig "konfigurieren" muss, ich habe dies mit diesen Zeilen versucht
gpio_configure_pin(SPI_NPCS1_PA31_GPIO, SPI_NPCS1_PA31_FLAGS);
gpio_set_pin_high(SPI_NPCS1_PA31_GPIO);
Mein Code bisher.
#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
Im Moment versuche ich, die Spi-Uhr / Ausgabe richtig einzustellen. Habe ich etwas verpasst?
Ihnen fehlt das GPIO-Setup. Sie dürfen die GPIO-Funktion NICHT zuweisen, aber Sie müssen dem Pin mitteilen, welche alternative Funktion er tatsächlich hat. Das wird etwas in der Art sein:
#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 hat ein ziemlich gutes Beispiel-Repository. Starten Sie Atmel Studio, wählen Sie ein neues Beispielprojekt aus, wählen Sie Ihren Controller oder Ihr Board aus und laden Sie etwas, das sich auf die Komponente bezieht, die Sie implementieren (in Ihrem Fall SPI). Folgen Sie dann "main", bis Sie zu dem Punkt kommen, der Sie interessiert. Von da an ist es normalerweise einfach.
Wenn sich ein Pin aus irgendeinem Grund nicht bewegt, ist die beste Vermutung, dass Sie Ihr GPIO (oder eine alternative Ping-Konfiguration) falsch eingerichtet haben.
Es scheint, dass sich der SAM4S ein wenig vom SAM4L unterscheidet. Wenn Sie sich das mitgelieferte SPI-Beispiel aus dem ASF ansehen, sehen Sie die Init-Sequenz (Funktion board_init() in SPI_EXAMPLE1\src\ASF\sam\boards\sam4s_ek\init.c) wie folgt:
/* 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);
Um tatsächlich mit einem Gerät zu sprechen, müssen Sie dieses Gerät auswählen (dies tut spi_set_peripheral_chip_select_value, es enthält auch Logik, wenn Sie einen DEMUX an Bord haben, weshalb es das Makro spi_get_pcs verwendet). Da SPI_CHIP_SEL 0 ist, sprechen Sie mit jedem Gerät, das mit CS0 verbunden ist. Wenn Sie mit einem Gerät auf einer anderen Chipauswahlleitung sprechen möchten, müssen Sie diese Werte und Ihr GPIO-Setup entsprechend ändern.
Ihre erste Aufgabe besteht darin, die Chip-Select-Leitung niedrig zu halten. Wenn dies nicht getan wird, erhalten Sie niemals Daten vom Slave, da er denkt, dass Sie nicht mit ihm, sondern mit einem anderen Gerät auf demselben SPI-Bus sprechen.
spi_enable_loopback(SPI_MASTER_BASE)
um meine Daten aufzuspüren, aber ich habe immer noch 0x00 erhalten. sieht aus wie einige Konfiguration ist auch falschPIN_PC31B_SPI_NPCS0
PIN_PC31B_SPI_NPCS0 defines (like in my code, they named slightly different, but i can't find out an equivalent variable for the
MUX_`). Und ja, meine CS-Linie ändert sich nicht. Die MISO/SO-Linie sieht gut aus.#define SPI_CHIP_SEL 0
in #define SPI_CHIP_SEL 1
Code behebt dies. so viel kleine schritte zu gehen :) danke für deine tipps und hilfe. Ich markiere deine Antwort als richtig
norca