$ilent 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Всё дело в том, что не устраивает скорость передачи (делится на 2), вот и пришло в голову руками впихивать биты на ножки: MOSI PB5; MISO PB6; SCK PB7. младший в перёд, защёлка по фронту. У меня туго с операциями сдвига, компилятор ICC, подскажите плиз кто может. void transSPI(CMDT command, MyByte8T address, MyByte8T *buffer, MyByte8T len) { MyByte8T dummyRX = 0; MyByte8T dummyTX = 0xFF; if (len > 0x80 || len == 0) return; PORTB &= ~BIT(3); SPDR = command | (len & 0x7F); while(!(SPSR &(1 << SPIF))); dummyRX = SPDR; SPDR = address; while(!(SPSR &(1 << SPIF))); dummyRX = SPDR; switch(command) { case READ_CMD: while(len-- > 0) { SPDR = dummyTX; while(!(SPSR &(1 << SPIF))); *buffer++ = SPDR; } break; case WRITE_CMD: while(len-- > 0) { SPDR = *buffer++; while(!(SPSR &(1 << SPIF))); dummyRX = SPDR; } } PORTB |= 1<<PORTD3; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ksv198 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Всё дело в том, что не устраивает скорость передачи (делится на 2), вот и пришло в голову руками впихивать биты на ножки: MOSI PB5; MISO PB6; SCK PB7. младший в перёд, защёлка по фронту. Быстрее, чем аппаратный SPI не получится. Програмная реализация имеет смысл с точки зрения удобства разводки платы или если нужен еще один SPI. Вот примерчик рабочий мастера программного (правда на асме :) ). Удачи! spi.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
$ilent 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Быстрее, чем аппаратный SPI не получится. Удачи! Как это не получится, стандартный SPI делит такты на 2, а если руками подавать биты с каждим тактом, то скорость возрастет примерно в 2 раза. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Karl 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Быстрее, чем аппаратный SPI не получится. Удачи! Как это не получится, стандартный SPI делит такты на 2, а если руками подавать биты с каждим тактом, то скорость возрастет примерно в 2 раза. И как вы себе представляете передачу битов с каждыи тактом? :) А проверку, какой бит выставлять, между тактами делаете? :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
$ilent 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба ну конечно не с каждым, а через один. на PB7 выдавать клок 4 раза, на PB5 *buffer по битно + здвиг в права, слушать PB6. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
$ilent 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба подскажите как какое нить число по битно положить на PB5 к примеру. и всё, дальше я сам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Igor26 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба подскажите как какое нить число по битно положить на PB5 к примеру. и всё, дальше я сам. Может так? for(Count=0;Count<8;Count++) { Digit=Digit<<1; //Выставляю в порт значение флага переноса PORTB_Bit5=SREG_Bit0; } здесь Digit - выводимое число Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Ах вот в чем дело, у вас тут ICC оказывается? Конечно! Вы хоть в код, который он генерит, заглядывали? Если нет, то ничего удивительного, что пауза между байтами у вас больше в 10 раз чем длительность передачи байта ;) - это я из другой, поднятой вами, темы почерпнул... Берите IAR или GNU-C и пишите следующий код (для передачи) void send(char *p, char len) { char temp; if (!len) return; do { temp=*p++; while(SPSR&(1<<SPIF)); SPDR=temp; } while(--len); } Поверьте, у вас будет нормальная скорость... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ksv198 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Быстрее, чем аппаратный SPI не получится. Удачи! Как это не получится, стандартный SPI делит такты на 2, а если руками подавать биты с каждим тактом, то скорость возрастет примерно в 2 раза. SPI предполагает одновременную передачу и прием последовательности битов. По сути это закольцованный сдвиговый регистр, т.е. выдвинули один бит на передачу и тут же получили бит на прием. Таким образом программно надо как минимум сделать следующее: 1. выдвинуть бит на передачу; 2. выдать импульс синхронизации (SCK); 3. проанализировать и задвинуть принятый бит. А стандартный SPI делит такты на 2... Аппаратно быстрее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
$ilent 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Ах вот в чем дело, у вас тут ICC оказывается? Конечно! Вы хоть в код, который он генерит, заглядывали? Если нет, то ничего удивительного, что пауза между байтами у вас больше в 10 раз чем длительность передачи байта ;) - это я из другой, поднятой вами, темы почерпнул... Берите IAR или GNU-C и пишите следующий код (для передачи) Этот код был написан не мной и под WINAVR и был только перенесён мной на ICC без изменений. Не заработает ваш код, у меня вызовы 4-х параметровые, и по любому их надо собирать в нутри этой функции. И задержки у меня большие не потому, что руки кривые, а по тому, что так надо, и от них ни как не уйти. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Этот код был написан не мной и под WINAVR и был только перенесён мной на ICC без изменений. Не заработает ваш код, у меня вызовы 4-х параметровые, и по любому их надо собирать в нутри этой функции. И задержки у меня большие не потому, что руки кривые, а по тому, что так надо, и от них ни как не уйти. Как это - "так надо"? У вас быстродействие упало в 10 раз! Все из-за того, что вы неграмотно работаете с аппаратным SPI. Пока передается байт, надо готовить следующий, а не тупо ждать. В результате ваш код должен выглядеть так: void transSPI(CMDT command, MyByte8T address, MyByte8T *buffer, MyByte8T len) { MyByte8T dummyRX; MyByte8T dummyTX = 0xFF; if (len > 0x80 || len == 0) return; PORTB &= ~(1<<3); SPDR = command | (len & 0x7F); while(!(SPSR &(1 << SPIF))); SPDR = address; switch(command) { case READ_CMD: while(!(SPSR &(1 << SPIF))); SPDR=dummyTX; //Для приема первого байта if (--len) { do { while(!(SPSR &(1 << SPIF))); dummyRX=SPDR; SPDR=dummyTX; *buffer++=dummyRX; } while(--len); } while(!(SPSR &(1 << SPIF))); dummyRX=SPDR; *buffer++=dummyRX; break; case WRITE_CMD: do { dummyTX=*buffer++; while(!(SPSR &(1 << SPIF))); SPDR=dummyTX; } while(--len); break; } PORTB |= 1<<3; } Ну и конечно, возьмите IAR - код выглядит отлично: 3 typedef char CMDT; 4 typedef char MyByte8T; 5 6 #define READ_CMD 0x55 7 #define WRITE_CMD 0xAA 8 \ In segment CODE, align 2, keep-with-next 9 void transSPI(CMDT command, MyByte8T address, \ transSPI: 10 MyByte8T *buffer, MyByte8T len) 11 { \ 00000000 2F51 MOV R21, R17 12 MyByte8T dummyRX; 13 MyByte8T dummyTX = 0xFF; 14 15 if (len > 0x80 || len == 0) return; \ 00000002 3841 CPI R20, 129 \ 00000004 F560 BRCC ??transSPI_0 \ 00000006 2344 TST R20 \ 00000008 F151 BREQ ??transSPI_0 16 17 PORTB &= ~(1<<3); \ 0000000A 98C3 CBI 0x18, 0x03 18 19 SPDR = command | (len & 0x7F); \ 0000000C 2F14 MOV R17, R20 \ 0000000E 771F ANDI R17, 0x7F \ 00000010 2B10 OR R17, R16 \ 00000012 B91F OUT 0x0F, R17 20 while(!(SPSR &(1 << SPIF))); \ ??transSPI_1: \ 00000014 9B77 SBIS 0x0E, 0x07 \ 00000016 CFFE RJMP ??transSPI_1 21 SPDR = address; \ 00000018 B95F OUT 0x0F, R21 22 23 switch(command) \ 0000001A 5A0A SUBI R16, 170 \ 0000001C F0B9 BREQ ??transSPI_2 \ 0000001E 5A0B SUBI R16, 171 \ 00000020 F4E9 BRNE ??transSPI_3 24 { 25 case READ_CMD: 26 while(!(SPSR &(1 << SPIF))); \ ??transSPI_4: \ 00000022 9B77 SBIS 0x0E, 0x07 \ 00000024 CFFE RJMP ??transSPI_4 27 SPDR=dummyTX; //Для приема первого байта \ 00000026 EF0F LDI R16, 255 \ 00000028 B90F OUT 0x0F, R16 28 if (--len) \ 0000002A 954A DEC R20 \ 0000002C F049 BREQ ??transSPI_5 29 { 30 do 31 { 32 while(!(SPSR &(1 << SPIF))); \ ??transSPI_6: \ 0000002E 9B77 SBIS 0x0E, 0x07 \ 00000030 CFFE RJMP ??transSPI_6 33 dummyRX=SPDR; \ 00000032 B11F IN R17, 0x0F 34 SPDR=dummyTX; \ 00000034 B90F OUT 0x0F, R16 35 *buffer++=dummyRX; \ 00000036 01F9 MOVW R31:R30, R19:R18 \ 00000038 9311 ST Z+, R17 \ 0000003A 019F MOVW R19:R18, R31:R30 36 } 37 while(--len); \ 0000003C 954A DEC R20 \ 0000003E F7B9 BRNE ??transSPI_6 38 } 39 while(!(SPSR &(1 << SPIF))); \ ??transSPI_5: \ 00000040 9B77 SBIS 0x0E, 0x07 \ 00000042 CFFE RJMP ??transSPI_5 40 dummyRX=SPDR; \ 00000044 B11F IN R17, 0x0F 41 *buffer++=dummyRX; \ 00000046 01F9 MOVW R31:R30, R19:R18 \ 00000048 8310 ST Z, R17 \ 0000004A C008 RJMP ??transSPI_3 42 break; 43 case WRITE_CMD: 44 do 45 { 46 dummyTX=*buffer++; \ ??transSPI_2: \ 0000004C 01F9 MOVW R31:R30, R19:R18 \ 0000004E 9101 LD R16, Z+ \ 00000050 019F MOVW R19:R18, R31:R30 47 while(!(SPSR &(1 << SPIF))); \ ??transSPI_7: \ 00000052 9B77 SBIS 0x0E, 0x07 \ 00000054 CFFE RJMP ??transSPI_7 48 SPDR=dummyTX; \ 00000056 B90F OUT 0x0F, R16 49 } 50 while(--len); \ 00000058 954A DEC R20 \ 0000005A F7C1 BRNE ??transSPI_2 51 break; 52 } 53 PORTB |= 1<<3; \ ??transSPI_3: \ 0000005C 9AC3 SBI 0x18, 0x03 54 } \ ??transSPI_0: \ 0000005E 9508 RET А если __z модификатор поставить, то вообще ляпота: 3 typedef char CMDT; 4 typedef char MyByte8T; 5 6 #define READ_CMD 0x55 7 #define WRITE_CMD 0xAA 8 \ In segment CODE, align 2, keep-with-next 9 __z void transSPI(CMDT command, MyByte8T address, \ transSPI: 10 MyByte8T *buffer, MyByte8T len) 11 { \ 00000000 2F31 MOV R19, R17 12 MyByte8T dummyRX; 13 MyByte8T dummyTX = 0xFF; 14 15 if (len > 0x80 || len == 0) return; \ 00000002 3821 CPI R18, 129 \ 00000004 F538 BRCC ??transSPI_0 \ 00000006 2322 TST R18 \ 00000008 F129 BREQ ??transSPI_0 16 17 PORTB &= ~(1<<3); \ 0000000A 98C3 CBI 0x18, 0x03 18 19 SPDR = command | (len & 0x7F); \ 0000000C 2F12 MOV R17, R18 \ 0000000E 771F ANDI R17, 0x7F \ 00000010 2B10 OR R17, R16 \ 00000012 B91F OUT 0x0F, R17 20 while(!(SPSR &(1 << SPIF))); \ ??transSPI_1: \ 00000014 9B77 SBIS 0x0E, 0x07 \ 00000016 CFFE RJMP ??transSPI_1 21 SPDR = address; \ 00000018 B93F OUT 0x0F, R19 22 23 switch(command) \ 0000001A 5A0A SUBI R16, 170 \ 0000001C F0A1 BREQ ??transSPI_2 \ 0000001E 5A0B SUBI R16, 171 \ 00000020 F4C1 BRNE ??transSPI_3 24 { 25 case READ_CMD: 26 while(!(SPSR &(1 << SPIF))); \ ??transSPI_4: \ 00000022 9B77 SBIS 0x0E, 0x07 \ 00000024 CFFE RJMP ??transSPI_4 27 SPDR=dummyTX; //Для приема первого байта \ 00000026 EF0F LDI R16, 255 \ 00000028 B90F OUT 0x0F, R16 28 if (--len) \ 0000002A 952A DEC R18 \ 0000002C F039 BREQ ??transSPI_5 29 { 30 do 31 { 32 while(!(SPSR &(1 << SPIF))); \ ??transSPI_6: \ 0000002E 9B77 SBIS 0x0E, 0x07 \ 00000030 CFFE RJMP ??transSPI_6 33 dummyRX=SPDR; \ 00000032 B11F IN R17, 0x0F 34 SPDR=dummyTX; \ 00000034 B90F OUT 0x0F, R16 35 *buffer++=dummyRX; \ 00000036 9311 ST Z+, R17 36 } 37 while(--len); \ 00000038 952A DEC R18 \ 0000003A F7C9 BRNE ??transSPI_6 38 } 39 while(!(SPSR &(1 << SPIF))); \ ??transSPI_5: \ 0000003C 9B77 SBIS 0x0E, 0x07 \ 0000003E CFFE RJMP ??transSPI_5 40 dummyRX=SPDR; \ 00000040 B11F IN R17, 0x0F 41 *buffer++=dummyRX; \ 00000042 8310 ST Z, R17 \ 00000044 C006 RJMP ??transSPI_3 42 break; 43 case WRITE_CMD: 44 do 45 { 46 dummyTX=*buffer++; \ ??transSPI_2: \ 00000046 9101 LD R16, Z+ 47 while(!(SPSR &(1 << SPIF))); \ ??transSPI_7: \ 00000048 9B77 SBIS 0x0E, 0x07 \ 0000004A CFFE RJMP ??transSPI_7 48 SPDR=dummyTX; \ 0000004C B90F OUT 0x0F, R16 49 } 50 while(--len); \ 0000004E 952A DEC R18 \ 00000050 F7D1 BRNE ??transSPI_2 51 break; 52 } 53 PORTB |= 1<<3; \ ??transSPI_3: \ 00000052 9AC3 SBI 0x18, 0x03 54 } \ ??transSPI_0: \ 00000054 9508 RET Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
$ilent 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Не, всё дело в том, что мега16 работает с приёмопередатчиком, и я не могу отправлять в буфер приёмопередатчика ни чего пока не получу от него ответа, что он готов принять следующий пакет в 128 байт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Не, всё дело в том, что мега16 работает с приёмопередатчиком, и я не могу отправлять в буфер приёмопередатчика ни чего пока не получу от него ответа, что он готов принять следующий пакет в 128 байт. В вашем исходнике никаких опросов готовности нет, кроме того, вы пытаетесь оптимизировать только ввод/вывод пакета через SPI. Я вам предложил оптимальный код. ЗЫ Мне кажется, вы взялись за задачу, вам непосильную, по причине не(до)понимания предмета ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
$ilent 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба Да именно так, я пытаюсь уменьшить время затраченое на передачу пакета, а не время между пакетами. Вот код остоянного опроса, хоть он здесь не к чему: /** * NTRXUpdate: * * NTRXUpdate() operates the complete receive part of the driver. It serves * receiver interrupt flags and picks up the received frame. * * Returns: none * */ void NTRXUpdate (void) { MyBoolT recal; nanoInterrupt (); # ifdef CONFIG_TRAFFIC_LED UpdateLEDs (); # endif /* CONFIG_TRAFFIC_LED */ /* check if we need to recalibrate the nanoNET TRX chip */ # ifdef CONFIG_NTRX_AUTO_RECALIB recal = (calDelay == 0) ? TRUE : FALSE; # endif if (ntrxState == TxWAIT) { NTRXTxEnd (); } if (rcwd > 3) { # ifdef CONFIG_NTRX_AUTO_RECALIB tiRecal = hwclock() + calDelay; # endif recal = TRUE; NTRXAllCalibration (); rcwd = 0; TRIGGER_LED3(); } # ifdef CONFIG_NTRX_AUTO_RECALIB if (ntrxCal != NoCAL) { if (ntrxCal == AllCAL) { NTRXAllCalibration (); } else { if (ntrxCal == RxCAL) { NTRXRxLoCalibration (); } if (ntrxCal == TxCAL) { NTRXTxLoCalibration (); } } tiRecal = hwclock() + calDelay; recal = TRUE; } # endif /* check if nanoNET TRX chip has received valid data */ if ((rxIrq & RXENDIRQ) == RXENDIRQ ) { NTRXRxReceive (); //rxIrq = 0; } # ifdef CONFIG_NTRX_AUTO_RECALIB if (FALSE == recal) { if (tiRecal < hwclock()) { tiRecal = hwclock() + calDelay; recal = TRUE; NTRXAllCalibration (); # ifdef CONFIG_TRAFFIC_LED TRIGGER_LED3(); # endif rcwd = 0; } } # endif } /** * nanoInterrupt: * * nanoInterrupt() is an interrupt service routine of the nanochip. * It updates the TX and RX status flags. * */ void nanoInterrupt (void) { /* * we have received an interrupt and neede to find out what caused it */ NTRXReadSPI (Silbadero_TxIntsRawStat_O, ntrxIrqStatus, 2); /* * check if it was the transmitter */ if (txIrqStatus != 0) { /* * clear interrupts */ NTRXSetRegister (TRX_RST_TX_IRQ, txIrqStatus); if ((txIrqStatus & TX_IRQ_MASK) == TX_IRQ_MASK) { ntrxState = TxWAIT; } } /* * check if it was the reciever */ if (rxIrqStatus != 0) { /* * clear interrupts */ NTRXSetRegister (TRX_RST_RX_IRQ, rxIrqStatus); rxIrq |= rxIrqStatus & RX_IRQ_MASK; } } На счёт непосильной задачи: устройство у меня работает, на скорости ~787Кбит/с из 2Мбит/с. И как вижу я, есть единственный способ поднять скорость, это уменьшить период клока увеличением частоты SPI, т.к. радиоканал работает на 2Мбит/с. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorKossak 0 11 июля, 2006 Опубликовано 11 июля, 2006 · Жалоба По-моему лучше увеличить тактовую у МК (до 16 МГц) и использовать всё-таки встроенный SPI. Частота SPI в этом случае может быть поднята до 8 МГц. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться