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

MSP430. Грамотная реализация програмного SPI


Рекомендуемые сообщения

Приветствую всех.

Подскажите не совсем программисту (или совсем не программисту) как грамотно реализовать программный SPI. МК CC430F5137 + OLED дисплей WEH000802A от Winstar. Данные 10 бит. Аппаратный в контроллере позволяет только 8, выход свой написать. Написал, но мне это не нравиться, знаю что можно намного проще, но не нахожу решения. Да и как то странно с портами в этом контроллере работается, нельзя (или не знаю как) данные напрямую в порт кидать, типа P1.0 = 1; А только BITами оперировать??? Вот что у меня получилось, смеяться разрешается ))

//  Обработчик дисплея
//
// Маразм для програмного SPI
void SCL(uchar b) { if (b==1) (P1OUT |= BIT7); else P1OUT &= ~BIT7; } //Строб
void CSB(uchar b) { if (b==1) (P1OUT |= BIT4); else P1OUT &= ~BIT4; } //Выбор чипа
void SDI(uchar b) { if (b==1) (P1OUT |= BIT6); else P1OUT &= ~BIT6; } //Передаваемые данные
void SDO(uchar b) { if (b==1) (P1OUT |= BIT5); else P1OUT &= ~BIT5; } //Принимаемые данные




// Вывод управляющей команды для дисплея
void WriteCMD(uchar CMD)
{
  uchar i;
  CSB(0);
  SDI(0);                                      
  _delay_cycles(100);
  SCL(0);
  _delay_cycles(100);
  SCL(1);
  SDI(0);                                      
  _delay_cycles(100);
  SCL(0);
  _delay_cycles(100);
  SCL(1);
  _delay_cycles(100);
  for(i=0;i<8;i++)
  {
    uchar t = ((CMD>>(7-i)) & 0x01);  // Как уйти от переменной t ????? 
    SDI(t);
    SCL(0);
    _delay_cycles(100);
    SCL(1);
    _delay_cycles(100);
  }
  CSB(1);
}

/*============================================
Вывод одиночного символа на дисплей
============================================*/
void WriteOneDAT(uchar DAT)
{
  uchar i;;
  CSB(0);
  SDI(1);                                      
  _delay_cycles(100);
  SCL(0);
  _delay_cycles(100);
  SCL(1);
  SDI(0);                                      
  _delay_cycles(100);
  SCL(0);
  _delay_cycles(100);
  SCL(1);
  _delay_cycles(100);
  for(i=0;i<8;i++)
  {
    uchar t =((DAT>>(7-i)) & 0x01);
    SDI(t);
    SCL(0);
    _delay_cycles(100);
    SCL(1);
    _delay_cycles(100);
  }
  CSB(1);
}

Технически разница между Командой и Данными в первом бите SDI и объединить эти две функции наверно не проблема, но я уверен что это можно написать как то грамотнее ...  Как в этом контроллере с портами работать кроме как P1OUT |= BIT1 ??? Нельзя как то типа P1OUT_1 = 1;  ?? Где то в буржуйской литературе мапинг какой то проскакивал, но там я вообще не вьехал про что это, для чего это....

Заранее Всем Благодарен.

 

 

 

 

 

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

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

// маска последнего выводимого бита
#define LAST_BIT	(1<<10)
// макрос SDI() переделать так, чтобы он возвращал bool-уровень на пине
  
uint16_t spi_io(uint16_t data){
	uint16_t result = 0;
	for(uint16_t mask = 1; mask <= LAST_BIT; mask <<= 1){
		SDO(data & mask);
		SCL(1);
		result |= SDI() ? mask : 0;
		SCL(0);
	}
	return result;
}

Вам лишь надо уточнить, в том ли направлении в моём коде идет сдвиг и в нужном ли режиме устанавливается SCK.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

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

Я понимаю, но как я сказал - я совсем не программист, когда то давно писал на ассемблере.  Вот например Ваш код мне сложен для понимания, я его конечно раскурю, я Вам благодарен, но придумать я бы такое не смог.

Еще раз благодарю.

Еще бы кто по работе с портами просветил...

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

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Только что, SerYoga72 сказал:

Еще бы кто по работе с портами просветил...

А что с ними не так?

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

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

Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. 

Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств. Подробнее параметры и результаты тестов новой серии PLM по ссылке.

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Пример Порт 1 Пин 0

P1OUT |= BIT0 ;  // P1.0 установили в единицу

P1OUT &= ~BIT0; // Установили в ноль

Это хорошо для моргания одним светодиодом, но часто проще сразу записать 1 или 0 в нужный порт, типа

P1.0 = 1;  // Неужели подобное невозможно реализовать в MSP430 ??

Я как только не пробовал... И нигде не нахожу. Для реализации SPI пришлось создать четыре функции, я считаю это бредом каким то, если честно.

// Маразм для програмного SPI
void SCL(uchar b) { if (b==1) (P1OUT |= BIT7); else P1OUT &= ~BIT7; } //Строб
void CSB(uchar b) { if (b==1) (P1OUT |= BIT4); else P1OUT &= ~BIT4; } //Выбор чипа
void SDI(uchar b) { if (b==1) (P1OUT |= BIT6); else P1OUT &= ~BIT6; } //Передаваемые данные
void SDO(uchar b) { if (b==1) (P1OUT |= BIT5); else P1OUT &= ~BIT5; } //Принимаемые данные

И кстати, в Вашей версии реализации вот этот кусок почему то не работает: 

	SDO(data & mask);

Еще сильно не думал, но даже если data имеет значения 0xFFFF,   SDO все равно имеет значение 0, всегда ноль....  Даже примерно не могу понять почему...

Я использую CCS.  И кстати булевых переменных тут что то же нет? Обявления типа bool var;  выдает ошибку неопределенный тип.... 

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

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

41 минуту назад, SerYoga72 сказал:

И кстати, в Вашей версии реализации вот этот кусок почему то не работает

потому что данные data и mask 16-битные, а функцию вы определили с 8-битным параметром. и вообще, я рассчитывал, что SDO будет макросом, которому в общем-то плевать на разрядность...

41 минуту назад, SerYoga72 сказал:

P1.0 = 1;  // Неужели подобное невозможно реализовать в MSP430 ??

Такое вообще нельзя реализовать на языке Си - это вы насмотрелись "кода" на недосишном языке CVAVR. Если сильно-сильно хочется именно подобной записи, то придется попариться со структурами и указателями... Но я вам не буду этого советовать - у вас и так проблем хватает.

41 минуту назад, SerYoga72 сказал:

P1OUT |= BIT0 ;  // P1.0 установили в единицу

P1OUT &= ~BIT0; // Установили в ноль

А вот это самая что ни на есть кошерная запись для Си. Именно так и правильно манипулировать битами.

#define SDO(x)	do{ if(x) P1OUT |= BIT5; else P1OUT &= ~BIT5; } while(0)
#define SDI()	(P1IN & BIT7)
#define SCK(x)  do{ if(x) P1OUT |= BIT6; else P1OUT &= ~BIT6; } while(0)

Как-то так всего-навсего... Я не знаком с вашей платформой, но для SDI по-моему нельзя использовать порт вывода P1OUT... я написал P1IN, хотя не уверен, что это правильно...

Изменено пользователем ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

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

Заставил я это работать )). Благодарю.  Теперь вопрос для повышения общего уровня образованности так сказать, ну если Вы не против.:

Вы предлагаете такую реализацию:

18 часов назад, ARV сказал:

#define SDO(x) do{ if(x) P1OUT |= BIT5; else P1OUT &= ~BIT5; } while(0)

#define SDI() (P1IN & BIT7)

#define SCK(x) do{ if(x) P1OUT |= BIT6; else P1OUT &= ~BIT6; } while(0)

У меня реализовано так:

void SCL(uchar b) { if (b) (P1OUT |= BIT7); else P1OUT &= ~BIT7; } //Строб
void CSB(uchar b) { if (b) (P1OUT |= BIT4); else P1OUT &= ~BIT4; } //Выбор чипа
void SDO(uint b)  { if (b) (P1OUT |= BIT6); else P1OUT &= ~BIT6; } //Передаваемые данные

Чем Ваша реализация лучше? (Вопрос не для спора а для понимания) И для чего цикл do-while ?

По поводу SDI (принимаемых данных) Вы правы, просто я данные пока не собирался принимать и написал на автопилоте P1OUT.

Заранее благодарен.

P.S. Как уменьшить межстрочный интервал в форуме?

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

Я кажется понял, если я использую #define то при компиляции данный код вставляется в место вызова и перехода не происходит, а в моем случае происходит переход в функцию и возврат из нее, то есть так мы экономим процессорные тики, я правильно понял?

А для чего do-while ?

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

Да, макросы повышают быстродействие, ведь требования к SPI обычно "чем быстрее, тем лучше". А do-while - это кошерная перестраховка на всякий случай. Во многих случаях можно и без этого, и данный случай как раз такой, просто делаю по привычке. Обычно do-while актуально для  макросов, состоящих из нескольких операторов, и в данном случае не дает никаких преимуществ, т.к. оператор один.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

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

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

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

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

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

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

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

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...