Проблемы с SPI в STM32F0 (HAL)

Posted by Nosaer | Posted in , , ,

    Отличительной особенностью в работе с SPI в серии F0, является использование 16 битного режима при передаче данных:
Data buffer address alignment restriction:
      (#) In case more than 1 byte is requested to be transferred, the HAL SPI uses 16-bit access for data buffer.
          But there is no support for unaligned accesses on the Cortex-M0 processor.
          So, if the user wants to transfer more than 1 byte, it shall ensure that 16-bit aligned address is used for:
          (##) pData parameter in HAL_SPI_Transmit(), HAL_SPI_Transmit_IT(), HAL_SPI_Receive() and HAL_SPI_Receive_IT()
          (##) pTxData and pRxData parameters in HAL_SPI_TransmitReceive() and HAL_SPI_TransmitReceive_IT()
      (#) There is no such restriction when going through DMA by using HAL_SPI_Transmit_DMA(), HAL_SPI_Receive_DMA()
          and HAL_SPI_TransmitReceive_DMA().
    Функции  в HAL написаны так, чтобы при передаче массива данных по SPI данные передавались пачками по 2 байта.
    Не смотря на то, какой режим передачи вы выберете в STM32CubeMX, передаваться будет всегда по 2 байта. Разница только в том, что если в 8 битном режиме остался 1 байт для передачи данных, то он будет отправлен отдельно.
    Для режима приемо-передачи есть один нюанс, это флаг SPI_FLAG_RXNE. Вся загвоздка в том, что пока аппаратно не будет получено 2 байта, этот флаг не будет выставлен. А следовательно передача в этом месте зависнет и будет ждать прихода еще одного байта.
Для этого при передаче последнего байта, флаг SPI_FLAG_RXNE выставляется самостоятельно (программно).
    Но проблема в том, что это не работает.  Хотя и реализовано вроде бы все правильно.
Но при работе и использовании функций на передачу и приемо-передачу отладчик вываливается с ошибкой в вечный цикл.
    Проблема распространенная. Часто встречался с ней на форумах, но в большинстве своем решение сводится к тому, чтобы отказаться в данном случае от HAL и переписать функцию на SPL или CMSIS.
    Для функции HAL_SPI_Transmit, мне в свое время помогло полное отключение оптимизации. Но это явно не тот выход.
Решение у меня в данном случае такое:

Имеем:
  /* Transmit and Receive data in 8 Bit mode */
  else
  {
    if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01U))
    {
      if (hspi->TxXferCount > 1U)
      {
        hspi->Instance->DR = *((uint16_t *)pTxData);
        pTxData += sizeof(uint16_t);
        hspi->TxXferCount -= 2U;
      }
      else
      {
        *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++);
        hspi->TxXferCount--;
      }
    }
    while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U))
    {
      /* check TXE flag */
      if (txallowed && (hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)))
      {
        if (hspi->TxXferCount > 1U)
        {
          hspi->Instance->DR = *((uint16_t *)pTxData);
          pTxData += sizeof(uint16_t);
          hspi->TxXferCount -= 2U;
        }
        else
        {
          *(__IO uint8_t *)&hspi->Instance->DR = (*pTxData++);
          hspi->TxXferCount--;
        }
        /* Next Data is a reception (Rx). Tx not allowed */
        txallowed = 0U;
      }
      /* Wait until RXNE flag is reset */
      if ((hspi->RxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)))
      {
        if (hspi->RxXferCount > 1U)
        {
          *((uint16_t *)pRxData) = hspi->Instance->DR;
          pRxData += sizeof(uint16_t);
          hspi->RxXferCount -= 2U;
          if (hspi->RxXferCount <= 1U)
          {
            /* set fiforxthresold before to switch on 8 bit data size */
            SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);
          }
        }
        else
        {
          (*(uint8_t *)pRxData++) = *(__IO uint8_t *)&hspi->Instance->DR;
          hspi->RxXferCount--;
        }
        /* Next Data is a Transmission (Tx). Tx is allowed */
        txallowed = 1U;
      }
      if ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >=  Timeout))
      {
        errorcode = HAL_TIMEOUT;
        goto error;
      }
    }
  }

  После преобразования, имеем:
  /* Transmit and Receive data in 8 Bit mode */
else
{
while((hspi->TxXferCount > 0) || (hspi->RxXferCount > 0))
{
  /* check TXE flag */
  if((hspi->TxXferCount > 0) && ((hspi->Instance->SR & SPI_FLAG_TXE) == SPI_FLAG_TXE))
  {
    *(__IO uint8_t *)&hspi->Instance->DR = (*hspi->pTxBuffPtr++);
    hspi->TxXferCount--;
    /* Enable CRC Transmission */
    if((hspi->TxXferCount == 0) && (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE))
    {
    hspi->Instance->CR1 |= SPI_CR1_CRCNEXT;
    }
  }
      /* Wait until RXNE flag is reset */
      if((hspi->RxXferCount > 0) && ((hspi->Instance->SR & SPI_FLAG_RXNE) == SPI_FLAG_RXNE))
      {
        (*hspi->pRxBuffPtr++) =  *(__IO uint8_t *)&hspi->Instance->DR;
        hspi->RxXferCount--;
      }
      if ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >=  Timeout))
      {
        errorcode = HAL_TIMEOUT;
        goto error;
      }
    }
  }

    Если вникнуть в изменения, то можно увидеть что я исключил из функции проверки на количество байт для передачи и все время передаю по 1 байту, вместо 2.
    Возможно стоило бы как то более глубже вникнуть в проблему, и понять почему именно получаю ошибку, но мне было проще поступить таким образом. Если у кого то будет более элегантное или более простое решение, буду рад ознакомиться с этим. 

Ремонт шуруповерта Интерскол(Li-ion)

Posted by Nosaer | Posted in , , ,

    В результате попадания влаги в аккумулятор шуруповерта, коррозия постепенно разъела плату балансировки.
    Пытался восстановить видимые поврежденные участки перемычками и заменой неисправных элементов, но попытки не увенчались успехом. Грешу на какое нибудь переходное отверстие, коих на плате немерено. Да и сама плата визуально выглядит не очень. Огромное количество всевозможных элементов. На основных микросхемах спилили маркировки, огромное количество переходных отверстий. Схему найти не смог, а без схемы на этой плате разобраться так и не смог.  На самом сайте Интерскола, сообщают о не ремонтопригодности и предлагают купить новый аккумулятор.
    Аккумулятор в моем шуруповерте работает от 5 литиевых элементов типоразмера 18650 емкостью 1300 мАч каждый, от производителя HighStar. После 4 лет активной эксплуатации к элементам особых нареканий не было, но все же решил заменить на новые: LitoKala HG2 на 3000мАч. Элементы необходимо выбирать высокотоковые, я взял на 30 Ампер.
    На всеми известном китайском сайте нашел плату балласта на 5 элементов. Плата не большая, тем самым хорошо уместилась в родной корпус.
При желании можно найти и на 4 элемента и на 3 элемента и.т.д.
    В моем случае аккумулятор имеет 3 вывода. Красный и черный используются когда аккумулятор подключен к шуруповерту. Желтый и черный используются для зарядки аккумулятора.
    В зависимости от производителя, если верить форумам, может быть всего 2 провода. Либо так же три, но третий сигнализирует об окончании заряда, при превышении порогового значения напряжения либо температуры.
    Производитель платы балласта рекомендует 2 схемы подключения.
Для трехпроводного подключения:
И для двухпроводного подключения.
    В моем случае, подключить по первой схеме не получилось, так как у меня на  выводе для зарядки  21 Вольт, а на плате балласта вывод для подключения зарядки управляется по земле и должен иметь отрицательный потенциал. Поэтому решил P- и  C- замкнуть перемычкой, и соединить желтый и красный провода на разъеме аккумулятора.
    Необходимо уделить внимание на соединение между собой литиевых элементов. Перемычки с маленьким сечением легко прожгутся при первом же включении шуруповерта. Так же желательно сильно не перегревать элементы, а по возможность пользоваться контактной сваркой. Если контактной сварки нет, то понадобиться хороший флюс, который позволит подпаяться к элементам. Я использовал флюс: Kingbo RMA 218
    Во время зарядки аккумуляторов, на плате балласта по мере заряда будут загораться светодиоды. Когда загорятся все, аккумулятор будет заряжен полностью. В моем случае, Через минуту после того как загорелись все светодиоды, они все погасли и ток заряда перестал на них поступать. Об этом собственно сигнализировал и сам зарядник, на котором потух светодиод процесса зарядки.
    После первой зарядки желательно проверить прекращается ли подача тока на элементе по завершению заряда. У товарища был случай, когда один MOSFET пробило, и он продолжал заряжать аккумуляторы.
    Аналогичным способом можно переделать шуруповерт на NiMh аккумуляторах, под литье. Но тогда придется еще и менять само зарядное устройство.

STM32CubeProgrammer на замену ST-LINK Utility

Posted by Nosaer | Posted in , , ,

     В одной из моих разработок, служебные данные хранятся во внутренней Flash памяти микроконтроллера STM32. Периодически возникает необходимость, заменить одно устройство на другое, либо обновить прошивку. В этом случае, все служебные данные и настройки затрутся.
    Чтобы после перепрошивки или замене, новое устройство работало с теми же параметрами, что и предыдущие я решил вручную изменять все необходимые для меня значения по заданным адресам Flash памяти, благо их не так много.
    Подобная возможность есть в ST-LINK Utility. Просто подключаемся к устройству, забиваем необходимый адрес, загружаем страницу и в ручную двойным щелчком правим необходимые байты.
    К моему удивлению, подобное я смог провернуть только с контролером STM32F407, на моей отладочной плате Discovery.  Непосредственно в моих же устройствах используется STM32F030 и ST-LINK Utility наотрез отказывается править Flash в данном контроллере. Причем есть возможность изменять данные на N'ом количестве первых страниц, а на более старших страницах вадает ошибки: "Error occured during memory writing".
    В течении нескольких дней перелистывал мануалы, и менял настройки в ST-LINK Utility, задавал вопросы на форумах, но так и не смог реализовать задуманное. Но буквально дней 10 назад в ленте увидел анонс STM32CubeProgrammer. Название заинтересовало, к тому же я активно использую STM32CubeMX. Да и из описания следовало, что это своеобразная альтернатива ST-LINK Utility.
    Стянул установочник с официального сайта. Перед установкой попросила обновить Java до последней версии и предложила дополнительно поставить Trusted Package Creator.
После установки видим весьма дружелюбный и понятный интерфейс:
    Программатор моментально определился, нажимаю Connect и программа мне выдает ошибку, в которой говорит, что я использую старый программатор. Меняю китайский ST-Link на ST-Link, что стоит на плате Discovery, результат тот же.  Хотя прошивку на самом программаторе обновлял через ST-LINK Utility буквально месяц назад.
    Нажал  Firmware Upgrade, пару раз попросили переподключить программатор, и все. Свежая прошивка в программаторе. Нажимаю еще раз Connect, происходит подключение уже к моему устройству.
    На вкладке Device Memory загружается Flash моего контроллера. Первым же делом перехожу по интересующему меня адресу и пытаюсь изменить необходимые мне ячейки. И о чудо, у меня получается. Никаких ошибок, все данные в устройстве.
    STM32CubeProgrammer более читабельный интерфейс, в сравнении с той же ST-LINK Utility.  Так сказать все на виду. И что больше всего мне понравилось, так это описание всех Option Byte. Если в ST-LINK Utility мы видим просто окно со всякого рода значениями, и чтобы разобраться в них нужно лезть в документацию. То здесь напротив каждого значения есть краткое описание.
    И еще одним преимуществом для меня я считаю возможность выбора из всплывающего списка, программатора, с которым в данный момент необходимо работать. На тот случай, если их подсоединено несколько штук. В ST-LINK Utility, такой возможности не было и периодически у меня возникала путаница.
     П.С. Позже пробовал повторить тоже самое заново в ST-LINK Utility, думал возможно это как то связано с прошивкой программатора, но так ничего у меня не получилось.
  

Вывод информации через SWO в KEIL(STM32)

Posted by Nosaer | Posted in , , ,

    Обычно я для подобных нужд использовал один из UART'ов. А здесь наткнулся на подобное в одном из вебинаров, и решил записать в качестве заметки.
    Выводить информацию в STM32 можно через специальный вывод SWO программного интерфейса SWD.
 В первую очередь необходимо настроить отладчик в самом Keil, согласно скриншотам:
  
    Стоит обратить внимание на использование SW, вместо JTAG. И на последнем скриншоте необходимо выставить частоту на которой работает процессор, а не  какой кварц используется. И соответственно выставить какой порт будет использоваться . Обычно ставят P0, но здесь особой разницы в принципе нет.
     Добавляем в проект, между /* USER CODE BEGIN Includes */ и /* USER CODE END Includes */:
#include 
#define ITM_Port8(n) (*((volatile unsigned char *)(0xE0000000+4*n)))
#define ITM_Port16(n) (*((volatile unsigned short*)(0xE0000000+4*n)))
#define ITM_Port32(n) (*((volatile unsigned long *)(0xE0000000+4*n)))
#define DEMCR (*((volatile unsigned long *)(0xE000EDFC)))
#define TRCENA 0x01000000

struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f) 

   {
       if (DEMCR & TRCENA)
        {
            while (ITM_Port32(0) == 0);
            ITM_Port8(0) = ch;
        }
    return(ch);
    }

    Затем в проекте в необходимых местах выводим необходимую нам информацию. Главное использовать после функции SystemClock_Config();, В противном случае будем получать иерголифы:
printf("Start Init\n"); // Для вывода текста
printf("%d\n",a); // Для вывода значений переменных

    Для самой отладки необходимо  перейти View -> Serial Windows -> Debug printf() Viewer, затем нажимаем Run(F5). И наблюдаем в появившемся окне все то, что прописали на вывод.
     Почему то во всех источниках предлагают использовать STM32 ST-LINK Utility. Чтоб им воспользоваться необходимо точно так же запустить процесс отладки в Keil, потом закрыть его, открыть ST-LINK Utility, настроить его на тот же Port и частоту, что настраивали Keil и нажать Connect.

Обзор видеорегистратора Xiaomi Yi 1080P Car WiFi DVR

Posted by Nosaer | Posted in ,

     Приобрел по принципу наилучшее соответствие цена-качество.
    Покупался за 3500р., как выяснилось позже, можно было найти и дешевле, но я решил взять у проверенного продавца.
Характеристики за такие деньги просто сумасшедшие:
- Производитель Xiaomi
- Материал PC / ABS
- Размер 74 × 52.4 ×19.4 мм
- Вес 74 г
- Фиксация С помощью присосок на стекло
- Источник питания Автомобильный прикуриватель (12-24В)
- Фотообъектив F1.8 большая апертура, 165° ультра-широкоугольный объектив
- Процессор изображения YI A 12 двухъядерный + DSP чип, 3D шумоподавление
- Датчик изображения 1/2.7 дюйма, 3,0 × 3.0μm (микрометра), 4000mV / lux — s (ультра-чувствительный датчик изображения)
- Экран 2,7 дюймовый ЖК (TFT) дисплей, соотношение сторон экрана — 16:9, разрешение 960x240
- WDR (технология широкого динамического диапазона) 2-го поколения, e-HDR
- Емкость аккумулятора 240 мАч (литий-полимерный)
- Общая потребляемая мощность ≤ 4.0 Вт
- Длина кабеля питания 3,5 м
- Интерфейс питания Micro USB (5V / 1A)
- Датчик силы тяжести Встроенный высокоточный датчик с тремя осями
- Видео кодирование Кодирование H.264, MP4 формат
- Поддержка дополнительной памяти MicroSD карты 8 — 64 Гб
- Звук Встроенный высококачественный микрофон и динамик
- Сеть Wi-Fi 802.11n, поддержка беспроводных стандартов безопасности
- Беспроводной шифрование WEP / WPA / WPA2
- Поддержка платформ Android 4.1 или более поздние версии и IOS 7.0 или более поздние версии

     Посылку принес курьер СДЭК, прямо до двери.
    Интерфейс на китайском, но это лечится перепрошивкой. Да и нет нужды в этом, по картинкам все интуитивно понятно. Плюс есть русифицированная программа для телефона(об этом ниже).
    Попытка вставить в него флешку с телефона не увенчалась успехом, чудо китайской промышленности вывело сообщение, что с такими медленными флешками работать не будет. И попросил приобрести флешку классом не ниже 10 и со скоростью записи 80Мб/с(говорят при 45мб/с тоже работает).
    Поехал в магазин, купил Kingston microSDHC/SDXC UHS-I U3 90R/80W 32Гб, как выяснилось позже последнее поколение и самые шустрые у них в линейке. Смысл таких манипуляций в том, что регистратор способен писать на разрешении 2304*1296 30к/с. Весит такое видео не хило, и его нужно постоянно пихать на флешку, потому и такие требования.   Сразу стоит отметить, что снимать лучше при 1920*1080 60к/с, так как видео качеством выше не каждый компьютер в состоянии открыть, а тот который смог проигрывал с малозаметными тормозами.
    Из плюсов стоит отметить очень большой угол обзора. Как сказал один мой товарищ, если бы не стойки, то он бы еще и зеркала твои заснял.
    Очень хорошее качество звука, никакого шипения, кряхтения и шумов.
    Есть система ADAS, которая контролирует разметку дороги и материт вас на китайском если вы начинаете съезжать на обочину или на встречку . Эта опция отключается, так как явно не для наших дорог.
    Теперь касаемо Wi-Fi:
    Есть специальная программа, переведенная на русский язык. Устанавливаете ее, там интуитивно понятный интерфейс и куча видеомануалов по настройке, установке регистратора и.т.д. С помощью программы можно настраивать регистратор, есть настройки, которых нет в самом регистраторе. например не отображать на видеозаписи дату, время или марку регистратора.
    Можно подключиться к нему и смотреть через телефон то, что он видит записывать это и фотографировать. Сомнительная опция в плане полезности, но таких там много))
    Порадовал адаптер, который вставляется в розетку. Он на два выхода USB, вроде бы мелочь, а приятно. Раньше там стоял обычный адаптер через который я заряжал телефон. А теперь с одного и телефон в дороге заряжать могу и ведеорегистратор подключени.
    В общем покупкой доволен и всем рекомендую.
На просторах интернета найти видеозаписи для просмотра качества видео вообще не проблема.
    Дополнительно к регистратору можно докупить переходное кольцо и ультрафиолетовый фильтр. Чтоб на солнце картинка было более четкой.
    Покупался здесь. Продавец проверенный, так что рекомендую.