0
votes

I'm trying to emulate data from the 10-bit AEAT-6010 rotary encoder and send it out on the MISO pin of the SPI protocol on the ATtiny3217. The ATtiny act as a slave and receive a CLK and SS signal as input to respond to by outputting the data(encoder value). The encoder follows the SSI protocol to send data as shown below:

Encoder Timing Characteristics

The problem arrises when trying to send 10 bits voer the 8 bit SPI protocol on the ATtiny. The master of the SPI protocol is the TMS320F2808 chip and from it I receive 11 clock pulses and the SS signal. The measured signals and data is shown below:

Oscilloscope measurements

Here the data I try to send is 0b10 just for testing. I can see the correct data on the MISO line, but there is three 1's extra in the middle of the signal. This is with BUFEN=1 and BUFWR=1 in the SPI settings of the ATtiny as can be seen in the configuration below(without buffer mode the three 1's comes on the last 3 bits, and aslo the first bit(MSB) is read as a 1):

int8_t SPI_0_init()
{

    SPI0.CTRLA = 0 << SPI_CLK2X_bp    /* Enable Double Speed: disabled */
                 | 0 << SPI_DORD_bp   /* Data Order Setting: enabled */
                 | 1 << SPI_ENABLE_bp /* Enable Module: enabled */
                 | 0 << SPI_MASTER_bp /* SPI module in slave mode */
                 | SPI_PRESC_DIV4_gc; /* System Clock / 4 */

    SPI0.CTRLB = 1 << SPI_BUFEN_bp   /* Buffer Mode Enable: enabled */
                 | 1 << SPI_BUFWR_bp /* Buffer Write Mode: enabled */
                 | SPI_MODE_0_gc     /* SPI Mode 1 */
                 | 0 << SPI_SSD_bp;  /* Slave Select Disable: disabled */

    SPI0.INTCTRL = 0 << SPI_DREIE_bp    /* Data Register Empty Interrupt Enable: enabled */
                   | 1 << SPI_IE_bp     /* Interrupt Enable: enabled */
                   | 0 << SPI_RXCIE_bp  /* Receive Complete Interrupt Enable: disabled */
                   | 0 << SPI_SSIE_bp   /* Slave Select Trigger Interrupt Enable: disabled */
                   | 0 << SPI_TXCIE_bp; /* Transfer Complete Interrupt Enable: disabled */

    return 0;
}

I have confirmed that the data fromat of the SPI module of the TMS320F2808 and the ATtiny is the same(read on falling clock edge). Is there something I am missing about how the buffers of the SPI work or the interrupts of the SPI? I'm not sure what to to in the ISR when enabling different interrupts(oher than clearing the flags). This is my main function(The ISR is empty for now):

int main(void)
{
    /* Initializes MCU, drivers and middleware */
    atmel_start_init();

    sei(); // Enable global interrupts

    /* Replace with your application code */
    while (1) {

        SPI_transmit(enc_data_L);

}

Where the SPI_transmit() is as follows:

void SPI_transmit(uint16_t enc_data)
{
    // Then start the transmission by assigning the data to the SPI data register
    SPI0.DATA = enc_data;
    //SPI0.DATA = enc_data_H;

    // Now wait for the data transmission to complete by periodically checking the SPI status register
    //the SPI_IF is the only interrupt flag with a function in non-buffered mode.
    while(!(SPI0.INTFLAGS & (SPI_RXCIF_bm)));
    SPI0.DATA; //Dummy read to clear flag
}

I have also tried splitting the 16 bit data, as suggested here, but the problem remains also for 8-bit data. Hope this is enough background info. I'm thankful for any ideas!

1

1 Answers

2
votes

in SPI_transmit after writing to the buffer you're waiting until transmission is completed. After that the input buffer is being fully transmitted and now is empty.

  while(!(SPI0.INTFLAGS & (SPI_RXCIF_bm))); // waits until data is transmitted

RXCIF is set when there is a data in the receive buffer, i.e. the transmission of the output buffer was also completed. Therefore, when next byte is being transmitted by the master, there is no new data yet in the output buffer to transmit. Probably the SPI module just repeats transmission of the previous byte.

So, instead of waiting for RXCIF flag, wait for DREIF flag, which will be set, when the transmission buffer is empty and ready for the next byte. You can just ignore the incoming data, since you're not use it anyhow

void SPI_transmit(uint16_t enc_data)
{
    // Wait until buffer is ready to get the next data byte
    while(!(SPI0.INTFLAGS & (SPI_DREIF_bm))); 

    // Then start the transmission by assigning the data to the SPI data register
    SPI0.DATA = enc_data;

    // Don't care about read buffer
}