Перейти к содержанию
    

LPC1111, тормоза SPI

Копаюсь с модулем SSP0 на контроллере LPC1111.

 

 

Частота камня - 48 МГц, частота SPI - 12 МГц, задержки между байтами 1,17 мкс.

post-35877-1322754246_thumb.png

 

 

Частота камня - 36 МГц, частота SPI - 18 МГц, задержки между байтами 1,23 мкс.

post-35877-1322754251_thumb.png

 

 

 

код простейший, никаких прерываний:

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;
}

 

Сталкивался кто-нибудь?..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Заглянуть в продуцируемый компилятором код не позволяет религия?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему же, заглядывал. Надо было сразу написать, что там ничего интересного не найдено.

 

                  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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Надо было сразу написать, что там ничего интересного не найдено.

 

Поганенько, конечно. uint8_t замените на uint_fast8_t да заинлайньте SendByteSPI. Но что-то мне кажется, что полста тактов оверхеда там не наберется. Чуть позже гляну в ман на проца, может чего подскажу еще.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

while( LPC_SSP0->SR & BIT(4) )    // SPI0 busy

я бы заменил на

while( (LPC_SSP0->SR & BIT(2)) == 0 )    // SPI0 busy

Т.е. ждал бы прихода байта, а не IDLE состояния.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

я бы заменил
А я бы проверял TNF и эту проверку на готовность к передаче поставил перед записью в DR.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А я бы проверял TNF и эту проверку на готовность к передаче поставил перед записью в DR.

Если слать побайтно и ждать приема ответного байта, то можно обойтимь одной проверкой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уже второй день сижу, экспериментирую... Ну да ладно, пятница :)

 

Закономерности выявить не удалось.

При частоте ядра 48 и 36 МГц разница незначительная, а при снижении до 24 МГц задержка возрастает до 1,8 мкс.

 

uint8_t замените на uint_fast8_t да заинлайньте SendByteSPI.

Сделал так, получил 0,9 мкс задержки.

 

Т.е. ждал бы прихода байта, а не IDLE состояния.

И ещё одна десятая микросекунды в выигрыше. Почему, мне не ясно...

 

 

При выкидывании проверки вообще получаем промежуток между клоками 80 наносекунд. Только, разумеется, ничего не работает ;-)

 

 

А я бы проверял TNF и эту проверку на готовность к передаче поставил перед записью в DR.

Идею не понял. А читаемые данные как достать? Там же FIFO, всё перепутается...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

При выкидывании проверки вообще получаем промежуток между клоками 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;
}

 

Типа такого.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не взлетит :(

Запихать в 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;
}

 

При попытке свернуть чтение в цикл получаем неплохие тормоза...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

При попытке свернуть чтение в цикл получаем неплохие тормоза...

 

А зачем в цикл сворачивать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Неверно выразился. Сначала была комбинация из

while (LPC_SSP0->SR & BIT(4));
while(LPC_SSP0->SR & (1<<2))
   ucByteReadMem=LPC_SSP0->DR;

А потом я второй цикл развернул, стало заметно быстрее.

 

В итоге: было 7 мкс, стало 4,5. С одной стороны - неплохо. А с другой - я два дня страдал фигнёй, ускорив первичную инициализацию аж на 30 миллисекунд. Всё остальное время обмен небольшой, пользователь потерпит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...