Hello e2e,
I am currently working on a program that sends data over the EUSCI_B0 peripheral in SPI mode. The transmission is interrupt-driven. The functionality is as following: In main(), a function initDDS() is called, which adds two bytes to the send buffer with the help of the function SPI_send(). SPI_send() then enables the interrupt, prompting a transmission of the bytes. I am using DriverLib V.3_21_00_05.
I have come across a very odd problem that I can't solve on my own. When debugging the program, SPI_send() adds the two bytes of initDDS() and the transmission works fine, but the function SPI_send() never returns. The function following initDDS(), write_freq() is never called.
When suspending the program execution, the debug call stack points to the last instruction of SPI_send(), which is __no_operation() in line 77. When resuming the program, the program continues executing as normal.
Setting breakpoints before and after EUSCI_B_SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_SPI_TRANSMIT_INTERRUPT) in line 76, as well as in the IRQHandler shows that the IRQHandler is called three times (as expected), before the freeze appears.
I'm suspecting that the cause lies in the interrupt, as I have tried replacing the EUSCI_B_SPI_enableInterrupt() for EUSCI_B0->IE |= EUSCI_B__TXIE; with no success. I've also tried adding return() to all functions as a last desperate attempt but that didn't change a thing.
Please help me out, I have no ideas left.
Greetings, Andy
Edit: As I closed CCS, a NullPointer Exception occured. Could CCS be the root of the problem? Maybe a earlier breakpoint that wasn't cleared correctly?
//main.c #include "driverlib.h" /* Standard Includes */ #include <stdint.h> #include <stdbool.h> #define FSYNC GPIO_PIN4 /* * PINS: * * DDS-part of board * P2.7 - BufEn1 * P2.6 - BufEn2 * P2.5 - ClkSt * P2.4 - FSYNC (equiv. of slave select) * P5.7 - FSEL * P5.6 - PSEL * P5.0 - SLEEP * P5.1 - RESET * P1.6 - SPI Master out * P1.7 - SPI Master in * P1.5 - SPI CLK * * Main part of board * P4.0 - p00 * P4.1 - P01 * P4.2 - P02 * P4.3 - P03 * P4.4 - B0 * P4.5 - B1 * P4.6 - B2 * P4.7 - B3 * P6.0 - Sel SR0 * P6.1 - Sel TG * P6.4 - Sel SR1 */ /* SPI Master Configuration Parameter */ const eUSCI_SPI_MasterConfig spiMasterConfig = { EUSCI_B_SPI_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 12000000, // SMCLK = 12MHZ 12000, // SPICLK = 12khz EUSCI_B_SPI_MSB_FIRST, // MSB First EUSCI_A_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT, // Phase EUSCI_SPI_CLOCKPOLARITY_INACTIVITY_HIGH, // High polarity EUSCI_B_SPI_3PIN // 3Wire SPI Mode }; uint8_t spi_sendbuffer[100]; uint8_t spi_buffer_end = 0; //Jerry uint8_t spi_next_index = 0; //Tom //Tom rennt immer Jerry hinterher. (Wie in der Zeichentrickserie Tom&Jerry) void SPI_send(uint8_t sequence[], uint8_t length) { SPI_disableInterrupt(EUSCI_B0_BASE, EUSCI_SPI_TRANSMIT_INTERRUPT); int i; int checked_length; if (length % 2 != 0) { //Die zu übertragenden Daten dürfen nur Vielfache von 2 Byte sein! checked_length = length -1; } else { checked_length = length; } for (i = 0; i < checked_length; i++) { spi_sendbuffer[spi_buffer_end + i] = sequence[i]; } //Das Null-Byte muss hinzugefügt werden, da sonst FSYNC HIGH wird während das letzte Byte sendet spi_sendbuffer[spi_buffer_end + checked_length] = 0x00; spi_buffer_end += checked_length +1; //EUSCI_B_SPI_enableInterrupt EUSCI_B_SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_SPI_TRANSMIT_INTERRUPT); __no_operation(); } void EUSCIB0_IRQHandler(void) { uint32_t status = SPI_getEnabledInterruptStatus(EUSCI_B0_BASE); SPI_clearInterruptFlag(EUSCI_B0_BASE, status); if(status & EUSCI_B_SPI_TRANSMIT_INTERRUPT) { uint8_t nextbyte = spi_sendbuffer[spi_next_index]; if (spi_next_index != spi_buffer_end || spi_next_index == 0) { if (spi_next_index % 2 == 0 && nextbyte != 0x00) { SPI_transmitData(EUSCI_B0_BASE, nextbyte); GPIO_setOutputLowOnPin(GPIO_PORT_P2, FSYNC); //Transfer started, pull FSYNC low } else { SPI_transmitData(EUSCI_B0_BASE, nextbyte); } spi_next_index++; } else { SPI_disableInterrupt(EUSCI_B0_BASE, EUSCI_SPI_TRANSMIT_INTERRUPT); GPIO_setOutputHighOnPin(GPIO_PORT_P2, FSYNC); //Transfer ended, pull FSYNC high spi_next_index = 0; spi_buffer_end = 0; } } } void init_DDS() { uint8_t initDDS[2] = {0x22,0x28}; SPI_send(initDDS, 2); } void write_phase(float phase, uint8_t register_nr) { /* * Diese Funktion nimmt als Argument: * phase: Die gewünschte Ausgangsphasenversatz * register_nr: Das Ziel-Register (0 oder 1). Zahlen über 1 werden als 1 gezählt. * Funktionsweise: Diese Funktion schreibt in ein Register eines AD9838 ein Phasenversatz des Sinussignals um 'phase' * Die Clock-Source muss 5MHz betragen. */ uint8_t reg_address = 0; if (register_nr == 0) { //siehe AD9838 Datenblatt S.19 reg_address |= 0b11000000; } else { reg_address |= 0b11100000; } uint16_t phasereg = 0; phasereg = (uint32_t) (phase * 651.8986469); uint8_t tosend[2]; tosend[1] = (uint8_t) phasereg; tosend[0] = (uint8_t) ((phasereg >> 8) & 0b00011111) | reg_address; SPI_send(tosend,2); } void write_freq(float frequency, uint8_t register_nr) { /* * Diese Funktion nimmt als Argument: * frequency: Die gewünschte Ausgangsfrequenz * register_nr: Das Ziel-Register (0 oder 1). * Funktionsweise: Diese Funktion schreibt in ein Register eines AD9838 ein Sinussignal mit der Frequenz * 'frequency'. * Die Clock-Source muss 5MHz betragen. */ /* static uint8_t prev_reg_nr; if (register_nr > 1) { register_nr = 1; } //This block is needed because with the B28 bit set, you cannot write to the same freqreg twice in a row. //See AD9838 Datasheet p.18 Table 7 if (prev_reg_nr == register_nr) { init_DDS(); } prev_reg_nr = register_nr; */ uint8_t reg_address = 0; if (register_nr == 0) { //siehe AD9838 Datenblatt S.19 reg_address |= 0b01000000; } else { reg_address |= 0b10000000; } uint32_t freqreg = 0; freqreg = (uint32_t) (frequency * 53.6870912); //Siehe AD9838 Datenblatt S.19 uint8_t tosend[4]; tosend[1] = (uint8_t) freqreg; tosend[0] = (uint8_t) ((freqreg >> 8) & 0b00111111) | reg_address; tosend[3] = (uint8_t) (freqreg >> 14); tosend[2] = (uint8_t) ((freqreg >> 22) & 0b00111111) | reg_address; SPI_send(tosend,4); } void main(void) { WDT_A_holdTimer(); Interrupt_disableMaster(); // Setting DCO to 48MHz PCM_setPowerState(PCM_AM_LDO_VCORE1); CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_48); // Set smclk to 12MHz CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1); CS_initClockSignal(CS_HSMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1); CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_4); CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1); // PORT 1 // selecting P1.5 P1.6 and P1.7 in SPI mode GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION); // PORT 2 GPIO_setAsOutputPin(GPIO_PORT_P2, FSYNC | GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7); GPIO_setOutputHighOnPin(GPIO_PORT_P2, FSYNC | GPIO_PIN5 | GPIO_PIN6); GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN7); // PORT 4 GPIO_setAsOutputPin(GPIO_PORT_P4, PIN_ALL8); // PORT 5 GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN6 | GPIO_PIN7); GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN6 | GPIO_PIN7); GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN0 | GPIO_PIN1); // PORT 6 GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN4); // SPI - EUSCI_B0 SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig); SPI_enableModule(EUSCI_B0_BASE); Interrupt_enableInterrupt(INT_EUSCIB0); Interrupt_enableSleepOnIsrExit(); Interrupt_enableMaster(); while(1) { __no_operation(); init_DDS(); write_freq(100000,0); while(1); //EUSCI_B0->TXBUF = 0xAA; //0xAA = 10101010 } //Writing to EUSCI_B0->TXBUF starts send }