esaulenka 7 1 декабря, 2011 Опубликовано 1 декабря, 2011 · Жалоба Копаюсь с модулем SSP0 на контроллере LPC1111. Частота камня - 48 МГц, частота SPI - 12 МГц, задержки между байтами 1,17 мкс. Частота камня - 36 МГц, частота SPI - 18 МГц, задержки между байтами 1,23 мкс. код простейший, никаких прерываний: uint8_t SendByteSPI( uint8_t data) { LPC_SSP0->DR = data; while( LPC_SSP0->SR & BIT(4) ) // SPI0 busy ; return LPC_SSP0->DR; } #define SPI_WriteByte(data) SendByteSPI(data) #define SPI_ReadByte() SendByteSPI(0x00) uint8_t Mem_ReadByte( uint32_t aunMemAddr ) { uint8_t ucByteReadMem; ACTIVE_SPI(); SPI_WriteByte( 0x03 ); // Read Data Bytes SPI_WriteByte( (uint8_t)(aunMemAddr >> 16 ) ); SPI_WriteByte( (uint8_t)(aunMemAddr >> 8 ) ); SPI_WriteByte( (uint8_t)(aunMemAddr ) ); ucByteReadMem = SPI_ReadByte(); DEACTIVE_SPI(); return ucByteReadMem; } Сталкивался кто-нибудь?.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 1 декабря, 2011 Опубликовано 1 декабря, 2011 · Жалоба Заглянуть в продуцируемый компилятором код не позволяет религия? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 1 декабря, 2011 Опубликовано 1 декабря, 2011 · Жалоба Почему же, заглядывал. Надо было сразу написать, что там ничего интересного не найдено. SendByteSPI PROC ;;;47 uint8_t SendByteSPI( uint8_t data) 000000 4903 LDR r1,|L2.16| ;;;48 { ;;;49 LPC_SSP0->DR = data; 000002 6088 STR r0,[r1,#8] |L2.4| ;;;52 while( LPC_SSP0->SR & BIT(4) ) 000004 68c8 LDR r0,[r1,#0xc] 000006 06c0 LSLS r0,r0,#27 000008 d4fc BMI |L2.4| ;;;53 ; ;;;59 return LPC_SSP0->DR; 00000a 6888 LDR r0,[r1,#8] 00000c b2c0 UXTB r0,r0 ;;;60 } 00000e 4770 BX lr ENDP |L2.16| DCD 0x40040000 Mem_ReadByte PROC ;;;171 // ;;;172 uint8_t Mem_ReadByte( uint32_t aunMemAddr ) 000000 b5f8 PUSH {r3-r7,lr} ;;;173 { ;;;174 uint8_t ucByteReadMem; ;;;175 ;;;176 ACTIVE_SPI(); 000002 2405 MOVS r4,#5 000004 4e0d LDR r6,|L6.60| 000006 0724 LSLS r4,r4,#28 000008 4605 MOV r5,r0 ;173 00000a 6126 STR r6,[r4,#0x10] 00000c 6126 STR r6,[r4,#0x10] 00000e 2700 MOVS r7,#0 000010 6127 STR r7,[r4,#0x10] ;;;177 ;;;178 SPI_WriteByte( 0x03 ); // Read Data Bytes 000012 2003 MOVS r0,#3 000014 f7fffffe BL SendByteSPI ;;;179 SPI_WriteByte( (uint8_t)(aunMemAddr >> 16 ) ); 000018 0228 LSLS r0,r5,#8 00001a 0e00 LSRS r0,r0,#24 00001c f7fffffe BL SendByteSPI ;;;180 SPI_WriteByte( (uint8_t)(aunMemAddr >> 8 ) ); 000020 0428 LSLS r0,r5,#16 000022 0e00 LSRS r0,r0,#24 000024 f7fffffe BL SendByteSPI ;;;181 SPI_WriteByte( (uint8_t)(aunMemAddr ) ); 000028 b2e8 UXTB r0,r5 00002a f7fffffe BL SendByteSPI ;;;182 ucByteReadMem = SPI_ReadByte(); 00002e 2000 MOVS r0,#0 000030 f7fffffe BL SendByteSPI ;;;183 ;;;184 DEACTIVE_SPI(); 000034 6127 STR r7,[r4,#0x10] 000036 6126 STR r6,[r4,#0x10] ;;;185 ;;;186 return ucByteReadMem; ;;;187 } 000038 bdf8 POP {r3-r7,pc} ;;;188 ENDP Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 1 декабря, 2011 Опубликовано 1 декабря, 2011 · Жалоба Надо было сразу написать, что там ничего интересного не найдено. Поганенько, конечно. uint8_t замените на uint_fast8_t да заинлайньте SendByteSPI. Но что-то мне кажется, что полста тактов оверхеда там не наберется. Чуть позже гляну в ман на проца, может чего подскажу еще. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Dron_Gus 2 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба while( LPC_SSP0->SR & BIT(4) ) // SPI0 busy я бы заменил на while( (LPC_SSP0->SR & BIT(2)) == 0 ) // SPI0 busy Т.е. ждал бы прихода байта, а не IDLE состояния. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 141 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба я бы заменилА я бы проверял TNF и эту проверку на готовность к передаче поставил перед записью в DR. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Dron_Gus 2 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба А я бы проверял TNF и эту проверку на готовность к передаче поставил перед записью в DR. Если слать побайтно и ждать приема ответного байта, то можно обойтимь одной проверкой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба Уже второй день сижу, экспериментирую... Ну да ладно, пятница :) Закономерности выявить не удалось. При частоте ядра 48 и 36 МГц разница незначительная, а при снижении до 24 МГц задержка возрастает до 1,8 мкс. uint8_t замените на uint_fast8_t да заинлайньте SendByteSPI. Сделал так, получил 0,9 мкс задержки. Т.е. ждал бы прихода байта, а не IDLE состояния. И ещё одна десятая микросекунды в выигрыше. Почему, мне не ясно... При выкидывании проверки вообще получаем промежуток между клоками 80 наносекунд. Только, разумеется, ничего не работает ;-) А я бы проверял TNF и эту проверку на готовность к передаче поставил перед записью в DR. Идею не понял. А читаемые данные как достать? Там же FIFO, всё перепутается... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба При выкидывании проверки вообще получаем промежуток между клоками 80 наносекунд. Только, разумеется, ничего не работает ;-) Ну и отлично. Пихаете 4 байта без проверок, и выгребаете все из RX, пока RNE=1 - последний байт будет Вашим. uint_fast8_t Mem_ReadByte( uint_fast32_t aunMemAddr ) { uint8_fast8_t ucByteReadMem; ACTIVE_SPI(); LPC_SSP0->DR = 0x03; LPC_SSP0->DR = aunMemAddr >> 16; LPC_SSP0->DR = aunMemAddr >> 8; LPC_SSP0->DR = aunMemAddr; LPC_SSP0->DR = 0; //Это для выгребания последнего байта. while(LPC_SSP0->SR & (1<<2)) ucByteReadMem=LPC_SSP0->DR; DEACTIVE_SPI(); return ucByteReadMem; } Типа такого. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба Не взлетит :( Запихать в FIFO 5 байт получается быстрее, чем он их передаёт. Соответственно, переходим к циклу выгребания, и возвращаем какой-то неверный байт. Но за идею спасибо, в итоге закончилось следующим: uint8_t Mem_ReadByte( uint32_t aunMemAddr ) { ACTIVE_SPI(); LPC_SSP0->DR = 0x03; LPC_SSP0->DR = aunMemAddr >> 16; LPC_SSP0->DR = aunMemAddr >> 8; LPC_SSP0->DR = aunMemAddr; LPC_SSP0->DR = 0; while (LPC_SSP0->SR & BIT(4)); DEACTIVE_SPI(); LPC_SSP0->DR; LPC_SSP0->DR; LPC_SSP0->DR; LPC_SSP0->DR; return LPC_SSP0->DR; } При попытке свернуть чтение в цикл получаем неплохие тормоза... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба При попытке свернуть чтение в цикл получаем неплохие тормоза... А зачем в цикл сворачивать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 2 декабря, 2011 Опубликовано 2 декабря, 2011 · Жалоба Неверно выразился. Сначала была комбинация из while (LPC_SSP0->SR & BIT(4)); while(LPC_SSP0->SR & (1<<2)) ucByteReadMem=LPC_SSP0->DR; А потом я второй цикл развернул, стало заметно быстрее. В итоге: было 7 мкс, стало 4,5. С одной стороны - неплохо. А с другой - я два дня страдал фигнёй, ускорив первичную инициализацию аж на 30 миллисекунд. Всё остальное время обмен небольшой, пользователь потерпит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться