Hello, All! I keep fighting with atmega162 and its SPI :) So now I configured slave mode. The purpose is to send 8 bytes one after another. I tested and debugged all code in simulator hundreds of times, I watched MCU registers, SPI registers and etc., everything seems to be fine, but after burning in chip - some weird problem. After receiving data from me, master is logging them onto the screen, so I can watch what's going on. Indeed it happenes, data got by master are strange and not what I sent. My chip is ATmega162, frequency 8MHz. Here is code: char *data = "123456780"; ... /* SPI init Mode: slave MISO: output MOSI: input SS: input SCK: input */ void SPI_SlaveInit(void) { DDRB = (1 << PB6); SPCR = (1 << SPIE) | (1 << SPE); // slave and enable SPI PORTB |= (1 << PB6); } void SPI_SendByte(char *data) { SPDR = *data; while ( !(SPSR & (1 << SPIF)) ) ; } SIGNAL(SIG_SPI) { char *t; t = data; while ( *data != 0 ) { SPI_SendByte((char *)data); data++; } data = t; LED0_blink(); // for debug: flush LED } int main(void) { sei(); SPI_SlaveInit(); ........ return 1; } And now I don't know, where is my problem has hidden. With best regards, Roman Mashak. E-mail: mrv@tusur.ru
SPI slave on ATmega162: transferring data
Started by ●December 9, 2004
Reply by ●December 9, 20042004-12-09
"Roman Mashak" <mrv@tusur.ru> wrote in message news:cp98r7$2ocg$1@mpeks.tomsk.su...> Hello, All! > > I keep fighting with atmega162 and its SPI :) > > So now I configured slave mode. The purpose is to send 8 bytes one after > another. I tested and debugged all code in simulator hundreds of times, I > watched MCU registers, SPI registers and etc., everything seems to befine,> but after burning in chip - some weird problem. > > After receiving data from me, master is logging them onto the screen, so I > can watch what's going on. Indeed it happenes, data got by master are > strange and not what I sent.What data is received, what do you see on the screen? Meindert
Reply by ●December 9, 20042004-12-09
>So now I configured slave mode.I have a feeling that the problem is that you aren't thinking how a slave should react. You are still thinking as if it is a master. A slave only responds to a request from a master. A slave does not initiate transfers. If you really want to see just your data come across, you need to setup the first data byte on initialization. When the master starts clocking, so will the slave. I don't know what triggers your SIG_SPI, maybe the toggling of SS? If so, then you have only the amount of time from the changing of SS to the Master starting to clock in order to get your data into the data register if it wasn't put there previously. I'm not sure what happens if you change the data register while the shifting is happening. Maybe the 162 will save it away in a buffer to be written after the transfer or maybe it won't allow the change, or maybe it will allow the change and the master will get some bits from the old data and some from the new data. And remember that the data register gets overwritten by watever the master sent. What you probably want to do in this specific case is: on slave init: setup for SPI Slave, then write first byte of data into SPDR. after transmission complete: get next data byte and write into SPDR for next transmission.> char *t; > > t = data; > while ( *data != 0 ) { > SPI_SendByte((char *)data); > data++; > } > data = t;Quite frankly, I also don't like this. You change the global variable "data" and then restore it. Why not just change the temporary "t" and do away with the restore? Only change a global if that side effect is required.
Reply by ●December 9, 20042004-12-09
Hello, Gary! You wrote on 09 Dec 2004 11:40:57 GMT: GK> If you really want to see just your data come across, you need to setup GK> the first data byte on initialization. When the master starts clocking, Do you mean, I should write byte into SPDR at my SPI_SlaveInit function? If so, should I also wait for transfer complete or at that stage it's quite enought just store value in the SPDR register? But if slave doesn't initiate a transfer it can silently wait for a moment when master starts transfer. I don't quite understand why should I write byte at slave init? GK> so will the slave. I don't know what triggers your SIG_SPI, maybe the GK> toggling of SS? If so, then you have only the amount of time from the As I understood datasheet, interrupt will be invoked as soon as transfer of byte will be completed. GK> changing of SS to the Master starting to clock in order to get your GK> data into the data register if it wasn't put there previously. I'm not [skip] GK> What you probably want to do in this specific case is: GK> on slave init: setup for SPI Slave, then write first byte of data into GK> SPDR. GK> after transmission complete: get next data byte and write into SPDR for GK> next transmission. ok, I'll follow your advice ??>> char *t; ??>> ??>> t = data; ??>> while ( *data != 0 ) { ??>> SPI_SendByte((char *)data); ??>> data++; ??>> } ??>> data = t; GK> Quite frankly, I also don't like this. You change the global variable "data" GK> and then restore it. Why not just change the temporary "t" and do away with the GK> restore? Only change a global if that side effect is required. In this case, may be it's better to declare 'char *t' as global volatile variable and use it, or it's rather useless ? With best regards, Roman Mashak. E-mail: mrv@tusur.ru
Reply by ●December 9, 20042004-12-09
Hello, Meindert! You wrote on Thu, 9 Dec 2004 11:55:22 +0100: ??>> After receiving data from me, master is logging them onto the screen, ??>> so I can watch what's going on. Indeed it happenes, data got by master ??>> are strange and not what I sent. MS> What data is received, what do you see on the screen? on the screen I see like this: 0x01 0x02 0x01 0x00 0x04 0x03 0x02 0x01 ans so on and from time to time the order of data is changed. With best regards, Roman Mashak. E-mail: mrv@tusur.ru
Reply by ●December 9, 20042004-12-09
Hello, Gary! You wrote on 09 Dec 2004 11:40:57 GMT: GK> And remember that the data register gets overwritten by watever the GK> master sent. GK> What you probably want to do in this specific case is: GK> on slave init: setup for SPI Slave, then write first byte of data into GK> SPDR. GK> after transmission complete: get next data byte and write into SPDR for GK> next transmission. I don't quite understand if I should check SPIF flag in case of interrupt driven code? With best regards, Roman Mashak. E-mail: mrv@tusur.ru
Reply by ●December 9, 20042004-12-09
"Roman Mashak" <mrv@tusur.ru> wrote in message news:cp98r7$2ocg$1@mpeks.tomsk.su...> Hello, All! > > I keep fighting with atmega162 and its SPI :)Below, you pass a pointer to a character:> void SPI_SendByte(char *data) > { > SPDR = *data; > while ( !(SPSR & (1 << SPIF)) ) > ; > } > > SIGNAL(SIG_SPI) > { > char *t; > > t = data; > while ( *data != 0 ) { > SPI_SendByte((char *)data);And here, you pass a character to SPI_SendByte, while it expects a pointer... Can't be right. Meindert
Reply by ●December 9, 20042004-12-09
Hello, Meindert! You wrote on Thu, 9 Dec 2004 13:58:24 +0100: MS> Below, you pass a pointer to a character: I changed the code and simplified a little, now I don't use pointers and send only one byte at all: ... char *t_data = "1"; void SPI_SendByte(char data) { SPDR = data; while ( !(SPSR & (1 << SPIF)) ) ; } SIGNAL(SIG_SPI) { SPI_SendByte(*t_data); ..... } nt main(void) { Timer1_Init(); sei(); // enable global interrupt SPI_SlaveInit(); // write first byte outside ISR to trigger interrupt SPI_SendByte(*t_data); while (1) { ... } } But still the same issue... With best regards, Roman Mashak. E-mail: mrv@tusur.ru
Reply by ●December 9, 20042004-12-09
"Roman Mashak" <mrv@tusur.ru> wrote in message news:cp9j6u$6tp$1@mpeks.tomsk.su...> Hello, Meindert! > You wrote on Thu, 9 Dec 2004 13:58:24 +0100: > > MS> Below, you pass a pointer to a character: > I changed the code and simplified a little, now I don't use pointers and > send only one byte at all: > > ... > char *t_data = "1"; > > void SPI_SendByte(char data) > { > SPDR = data; > while ( !(SPSR & (1 << SPIF)) ) > ; > } > > SIGNAL(SIG_SPI) > { > SPI_SendByte(*t_data); > ..... > } > > nt main(void) > { > Timer1_Init(); > sei(); // enable global interrupt > SPI_SlaveInit(); > > // write first byte outside ISR to trigger interrupt > SPI_SendByte(*t_data); > > while (1) > { > ... > } > } > > But still the same issue...The problem with the code above (I assume it is the code for the master) is that you call spi_sendbyte from within the interrupt handler. Spi_sendbyte waits for the SPIF flag. The moment this flag is set, another interrupt is issued while you are still inside spi_sendbyte. You can safely remove the while loop in spi_sendbyte because you only call it once at the start of the communication. After that it is called from the interrupt handler only when the shifter is empty. So, no need to wait for the SPIF flag. And when the while loop is removed, you'll that the only line left in spi_sendbyte can be put in the interrupt handler to save a pair of unnecessary call/return. Meindert
Reply by ●December 9, 20042004-12-09
Hello, Meindert! You wrote on Thu, 9 Dec 2004 14:40:44 +0100: MS> The problem with the code above (I assume it is the code for the MS> master) is that you call spi_sendbyte from within the interrupt this is code for slave MS> handler. Spi_sendbyte waits for the SPIF flag. The moment this flag is MS> set, another interrupt is issued while you are still inside MS> spi_sendbyte. You can safely remove the while loop in spi_sendbyte Alright, I understand you. Here is changed version, I hope is correct :) MS> because you only call it once at the start of the communication. After MS> that it is called from the interrupt handler only when the shifter is MS> empty. So, no need to wait for the SPIF flag. And when the while loop MS> is removed, you'll that the only line left in spi_sendbyte can be put MS> in the interrupt handler to save a pair of unnecessary call/return. char *t_data = "1"; ... SIGNAL(SIG_SPI) { SPDR = *t_data; LED0_blink(); // debugging feature } void SPI_SlaveInit(void) { DDRB = (1 << PB6); SPCR = (1 << SPIE) | (1 << SPE); // select slave and enable SPI PORTB |= (1 << PB6); } int main(void) { sei(); SPI_SlaveInit(); SPDR = *t_data; //write byte to trigger interrupt while (1) { ..... } return 1; } With best regards, Roman Mashak. E-mail: mrv@tusur.ru