Приятные на ощупь MSP430F2xx

Я работаю над новым проектом, в котором используется MSP430F2274. Не плохой, надо сказать, камушек! В этом проекте нужно отправлять пакеты данных в комп, а значит, что нужно подсчитывать у них контрольную сумму (далее — КС).

Пару лет назад я уже писал на тему подсчета КС блока данных. Тогда измерения скорости вычисления КС и оценка расхода памяти (RAM и flash) были выполнены для микроконтроллера AVR.

«CRC16-CCITT — сравнение реализаций»
http://wp.me/p1H7g0-C0

Сегодня я произвел те же измерения, но для MSP430.

Я думаю, что разработчикам будет не только интересно ознакомиться с результатами сравнения, но результаты дадут им твёрдую опору при выборе типа микроконтроллера для следующих проектов.

Для сравнения производительности были использованы следующие микроконтроллеры:

  • ATMEGA328, работающий на частоте 8 МГц
  • MSP430F2274, работающий на частоте 16 МГц

Я сразу прокомментирую такую разницу в тактовых частотах.

Дело в том, что для измерения использовалось готовое изделие, в котором MSP430 работает именно на такой тактовой частоте. Мне нужно было получить время вычисления КС прежде всего для работы, и уж только потом — для сравнения. Поэтому я не стал изменять частоту микроконтроллера.

Собственно, поскольку у названных микроконтроллеров нет механизма пропуска тактов при выборке из памяти (как у ARM-ов), то разница в тактовых частотах, на которых производились замеры, — не принципиальна для сравнения эффективности работы микроконтроллеров. Разные тактовые частоты — это всего лишь масштабный коэффициент.

Для вычисления контрольной суммы использовался блок данных размером 816 байт.

Такое странное количество объясняется тем, что измерения двухлетней давности производились на именно на таком количестве байт. Нынешние измерения меня ничем не ограничивали, поэтому я взял то же самое количество байт.

С качестве блока данных использовался буфер, заполненный байтами с возрастающими значениями: 0x00, 0x01, 0x02, 0x03 и так далее. Буфер размещался в оперативной памяти.

Я произвел измерения для обоих способов вычисления КС — и для программной реализации, и для табличной. В предыдущей статье о способах вычисления КС я упоминал, что для программной реализации вычисления КС требуется значительное большее количество времени, чем для табличной реализации. С другой сторон табличная реализация вычисления КС требует размещения таблицы кодов в памяти микроконтроллера.

Таблица для CRC16 имеет размер 512 байт, то есть соизмерима с размером оперативной памяти. Поэтому, для микроконтроллеров AVR табличный способ вычисления КС может оказаться вообще не реализуемой затеей — ведь для AVR, прежде чем работать с константами, их следует перенести из flash-памяти в оперативную. Иначе, никакой выгоды времени при вычислении по программному или табличному способу не будет.

Другое дело MSP430! Единое адресное пространство позволяет одинаково работать как с данными, которые размещены в оперативной памяти, так и с данными (константами), которые записаны во flash-памяти. Поэтому, для MSP430 (и для STM32) табличный способ вычисления КС будет более эффективен, чем для AVR.

Результаты измерения сведены в таблицу:

Микроконтроллер ATMEGA328 MSP430F2274
Частота, кГц 8000 16000
Время выполнения
Программный способ, мс 12,9 4,13
Табличный способ, мс 2,76 0,88
Количество тактов
Программный способ 103200 66080
Табличный способ 22080 14080

Даже если учесть, что микроконтроллеры могут работать на одинаковых тактовых частотах, то всё равно видно, что MSP430 работает более эффективно нежели ATMEGA328. Это хорошо видно при анализе количества тактов, затраченных на решение задачи — MSP430 эффективнее ATMEGA328 примерно в полтора раза.

А если учесть, что MSP430 имеет единое адресное пространство, то становится возможным использовать табличный способ вычисления КС не расходуя при этом весьма дорогую оперативную память. А это очень даже

Ну, разве это не конфетка!

 

Реклама

4 responses to “Приятные на ощупь MSP430F2xx

  1. > для AVR, прежде чем работать с константами, их следует
    > перенести из flash-памяти в оперативную. Иначе, никакой
    > выгоды времени при вычислении по программному или
    > табличному способу не будет.

    Загрузка из SRAM (ld) — 1 такт; загрузка из flash (lpm) — 3 такта. Вычисление будет всяко медленнее.

    • Такое ощущение, что Вам хочется поспорить. Ну, либо Вы ничего не поняли из статьи.

      В любом случае это означает одно — я не очень доходчиво изложил свои мысли. Что ж, попробую исправить ситуацию.

      Я говорил не о простых проектах, которые легко «поднимаются» на ассемблере. Я веду разговор об относительно сложных проектах, которые представляют собой десяток (и более) Си-шных файлов, общим размером не менее 2-3 тысяч строк.

      Как правило такие проекты пишутся на Си, а не на ассемблере.

      Не-е, конечно, «нАспор» можно написать такой проект и на ассемблере. Но я бы не сказал, что такой подход к коммерческим проектам есть серьезный подход. Я бы не стал этот случай рассматривать. Ведь смысл коммерческих проектов ведь не в том чтобы кому-то что-то доказать, а совершенно в ином.

      Представьте себе, что Вы трудитесь как раз над таким проектом, и Ваша очередная подзадача — написать код, который вычисляет контрольную сумму (далее — КС) у входящих и исходящих пакетов.

      В реализации механизма подсчета КС Вас никто не ограничивает. Вы можете написать код на Си, Вы можете написать код в виде ассемблерных ин-лайн вставок. Вы можете написать ассемблерный файл и включить его в проект. Вы можете даже воспользоваться готовой, уже кем-то написанной библиотекой. Свобода действий — полная!

      В своем проекте, Вы (лично Вы!) можете творить всё, что Вы сочтете нужным и правильным. Точно так же и я поступаю в своих проектах. Я пишу процедуру подсчета КС на том же языке, на котором написан весь остальной код проекта — то есть на Си. Это очень удобно в плане сопровождения, потому как всё единообразно (в хорошем смысле этого слова!)

      А раз я пишу на Си, то вопрос ассемблера даже не поднимается. А, собственно, зачем нужен ассемблер, если Си справляется с задачей?

      Другое дело — к какому методу подсчета КС мне следует прибегнуть: к табличному или к программному?

      Если опираться на программную реализацию, то MSP430 будет вычислять КС раза в полтора быстрее, чем AVR, при условии, что тактовые частоты у них одинаковые. То есть эффективность кода (который получается при компиляции Си-ных исходников) у MSP430 выше AVR-овского примерно раза в полтора.

      Если опираться на табличный метод вычисления КС, то здесь помимо той же полутора-кратной эффективности наблюдается еще и экономия оперативной памяти. 512 байт оперативной памяти — это достаточно ощутимый объем!

      Понимаете, спорить без доказательно — это только время терять. Пожалуйста, в качестве доказательства, что я не прав, приведите свой Си-шный код реализации подсчета КС. Возможно, Ваш код получится более легким и более понятным.

      У меня нет цели победить в споре. У меня цель — добраться до истины.

      • К сожалению, Вы совершенно неверно поняли посыл моего комментария, в чём есть и моя вина. Я не спорю с приведёнными в статье выкладками и не призываю писать какие-либо части проекта на ассемблере. Я лишь указал что проигрыш по времени между вариантом «держать таблицу во флеш-памяти» относительно варианта «держать таблицу в SRAM» составляет всего два такта при существенной экономии SRAM (512 байт), независимо от языка программирования. Прикладываю ссылку на пример реализации табличного метода вычисления CRC-16 для AVR с хранением таблицы в flash-памяти (без копирования в SRAM): paste.org.ru/?6kd852

      • Ага, ну, вот теперь понятно, что Вы имели в виду. Ну да, можно и так — по-байтно — добывать константы из флешь-памяти. Немного ещё теряем в быстродействии, но зато сэкономим оперативную память.

        Я помещу сюда Ваш код.

        #include 
        #include 
        
        #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
        
        // polynomial: 0x8005 (x^16 + x^15 + x^2 + 1) (modbus)
        const __flash uint16_t crc16_table[256] =
        {
            0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
            0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
            0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
            0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
            0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
            0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
            0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
            0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
            0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
            0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
            0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
            0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
            0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
            0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
            0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
            0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
            0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
            0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
            0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
            0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
            0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
            0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
            0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
            0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
            0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
            0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
            0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
            0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
            0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
            0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
            0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
            0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
        };
        
        static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data)
        {
            return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
        }
        
        uint16_t crc16(uint16_t crc, const uint8_t *buffer, uint16_t len)
        {
            while (len--)
                crc = crc16_byte(crc, *buffer++);
            return crc;
        }
        
        static const uint8_t array[] = { 1,2,3,4,5 };
        
        void main( void )
        {
            volatile uint16_t crc = crc16(0xffff, array, ARRAY_SIZE(array));
            while(1);
        }
        

        У меня сейчас под руками нет AVR, поэтому поиграться с кодом не могу. Разумеется, этот код рабочий. Сомнений нет. Другое дело, что я не могу оценить его эффективность.

        Еще раз. Вопросов, что возможно или не возможно реализовать на том или другом микроконтроллере вычисление КС, — не возникает! Практически любой контроллер позволяет это сделать. Вопрос в эффективности. Вопрос в том, на сколько эффективно тот или иной микроконтроллер делает эту работу.

        Я могу еще раз привести свои комментарии к коду вычисления CRC16. Вот они:

        Программная реализация:
        /*
        время вычисления 816 байт для ATMEGA328 на 8 MHz = 2.759 мс
        примерно 3.4 мкс на один байт или 27 тактов на один байт

        время вычисления 816 байт для MSP430F2274 на 16 MHz = 880 мкс
        примерно 1.08 мкс на один байт или 17 тактов на один байт
        */

        Табличная реализация:
        /*
        время вычисления 816 байт для ATMEGA328 на 8 MHz = 12.9 ms
        примерно 18.8 мкс на один байт или 126 тактов на один байт

        время вычисления 816 байт для MSP430F2274 на 16 MHz = 4.13 us
        примерно 5.06 мкс на один байт или 81 такт на один байт
        */

        Возможно когда-нибудь потом, когда я буду работать с каким-нибудь проектом на AVR, я попробую количественно (в тактах, в микросекундах) оценить Ваш код. Сейчас у меня несколько другие работы, поэтому пока никак.

        Спасибо Вам за Ваши комментарии!

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s