Estoy usando un dsPIC33 y solo quiero enviar datos SPI básicos. Sin Rx, solo Tx por ahora para controlar un digipot. El hardware incluye esclavo en el otro extremo, y estoy olfateando la salida con un analizador lógico. Acabo de ver, literalmente, 10 maneras diferentes de hacerlo, pero ninguna de ellas parece estar funcionando.
Problema: datos aleatorios que salen. De vez en cuando tiene sentido como un 3 o 7, pero por lo demás basura.
Tampoco estoy seguro de si está bien que la línea MOSI no siempre vuelva a un valor alto o bajo predeterminado. Por lo general, comienza alto, escribe datos, termina bajo, luego termina arriba en la siguiente ronda, lo que parece extraño.
Otro: cables cortos, ningún IC (potencialmente dañado) en el otro extremo, resistencia de pull-up de 10k en la línea de selección de chip (CS), la velocidad de transmisión más lenta posible (el valor predeterminado es el prescaler de spi y el postcaler), probado 8 y 16 en los modos de bits, probé todos los ajustes en el analizador lógico (primero MSb y primero LSb, etc.), los pines RPn no pueden ser analógicos por defecto, los pines RPn no son entrada RPn, ...
¿No es esto tan simple? ¿Qué podría faltar?
uint16_t main(void) {
UC_ConfigureOscillator();
TMRS_Init();
SPI_Init(38, 39);
// prime any timers that require it
TMRS_Start(TX_TIMER, TX_PERIOD);
volatile uint16_t val = 0;
// watch the data being transmitted with a logic analyzer
while (1) {
// periodically transmit a message
if (TMRS_Expired(TX_TIMER)) {
TMRS_Start(TX_TIMER, TX_PERIOD);
SPI_SendWord(val);
if (++val > 10) val = 0;
}
}
return 0;
}
void SPI_Init(uint8_t sdo_pin, uint8_t sck_pin) {
// Configure and initialize the chip-select pin
_TRISB8 = 0;
_LATB8 = 1;
// Configure the SPI clock and MOSI pins
__builtin_write_OSCCONL(OSCCON & 0xBF);
_RP39R = 0b001001;
_RP38R = 0b001000;
// Configure the interrupt
_SPI2IE = 0; // Disable the interrupt
_SPI2IF = 0; // Clear the interrupt flag
_SPI2IE = 1; // Enable interrupts for this spi module
_SPI2IP = 2; // Assign the interrupt priority
SPI2CON1bits.MODE16 = 1; // Use in 16-bit mode
SPI2CON1bits.MSTEN = 1; // Configure this device as master
SPI2STATbits.SPIROV = 0; // Ensure the receive overflow flag begins cleared
SPI2STATbits.SPIEN = 1; // Enable the SPI module
SPI2CON1bits.SMP = 1; // Sample input data at END of data output time
}
void SPI_SendWord(uint16_t word) {
uint16_t garbage;
// lower CS
_LATB8 = 0;
// write the given word to the Tx/Rx buffer
SPI2BUF = word;
// wait for the transmit buffer to clear
while (SPI2STATbits.SPITBF == 0);
// wait for the transmit to begin
while (SPI2STATbits.SPITBF == 1);
// Dummy-read the SPIxBUF register to clear flag???
garbage = SPI2BUF;
}
// Called on 16bits finished shifting in OR out of SPI2 buffer
void __attribute__((__interrupt__, auto_psv)) _SPI2Interrupt(void) {
// Return CS high
_LATB8 = 1;
// Clear the source of the interrupt
_SPI2IF = 0;
}