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

Realtime SSI slave 18bit+ STM3L4


Cujo

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

Собственно задача соорудить SSI slave Transmit only с асинхронным обновлением в реальном времени.
Контроллер сейчас STM32L433CC. 
Дано один вход SCLK до 2 МГц, один выход SOUT(он жеMISO). Формат посылки 18, 20,22 бит.
Обновление через ~15мкс после последнего такта SCLK, либо каждые 7,5 мкс.
Стандартный интерфейс для быстрых датчиков.
Как делал 
1: Без DMA и прерываний, по прерываниям от TIM_ETR на SCLK. Режим без NSS, с NSS по первому SCLK и сбросом.
Проблема нельзя узнать, записались ли данные в SPI->DR, соответственно первые байты могли быть не обновлены, а следующие обновлялись.
2: DMA с NSS по таймеру. Проблема: DMA не обновляет SPI в реальном времени, а только после отправки прошлой посылки, а нужно обновлять каждые 7,5 мкс вне зависимости есть ли запросы. 
Если пробовать сбрасывать SPI и обновлять DMA, случаются смещения на 1 такт, а потому как реакция ядра на запрос ~ 150-200 нс, + обновление ~ 150-200нс. В итоге облом.

Какие есть решения, может кто сталкивался?

 

Снимок.PNG

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

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

В 10.11.2018 в 21:31, Cujo сказал:

нельзя узнать, записались ли данные в SPI->DR,

Это как это? Если инструкция записи выполнена - данные записались!

Для того чтобы узнать когда они вышли на шину полностью есть флаг прерывания, что еще надо???

Вообще зачем нужен таймер? Используйте флаг опустошения буфера! Скорость SPI- настраивается, в том числе через задержки между байтами.

И для ДМА, кстати, тоже флаг опустошения буфера нужно использовать.

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

Можно сделать все! Но чем больше можно, тем больше нельзя!

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

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

на самом деле проблема уже решилась с помощью трех таймеров, программного прерывания 3х внешних соединений и кучи костылей, подробнее описал на easyelectronics, если интересно

 

Проблема в том что SPI->DR обновлять можно. Те на SPI будут выдаваться последний записанных DR. Но когда приходит такт SCLK, регистр блокируется и запись в него не осуществляется. И узнать об этом никак нельзя. А обновлять данные нужно не дожидаясь прихода SCLK, он может не приходить сколь угодно долго, но данные должны быть все время актуальные.

Дело в том, что на этом контроллере есть еще 2 потока с периодом вызова 7 и 14 мкс. Останавливать их никак нельзя, и главные прежде всего они. SPI нужен чтобы вывести информацию о их вычислениях, те о угле либо положении.  Стандартный протокол выдачи в таких случаях - это SSI, есть еще BISS C - тот же проприетарный SSI с контрольной суммой. 

В общем, тему можно закрывать. Плодить костыли по интернету как-то не хочется. STM сказал: "он не рекомендует использовать их МК для реализации SSI и работоспособность такой системы не гарантирована".

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

  • 5 месяцев спустя...

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

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

Если ещё интересно. Недавно пришлось с датчиком линейного перемещения столкнуться. Протокол SSI.

Сделал 2 варианта: 1)с использованием таймера и внешнего прерывания ; 2) с использованием SPI. 

С SPI конечно получше, больше времени на выполнение других задач остаётся, так как вместо 48 прерываний по передаче и ещё 25 прерываний по приёму для получения одного значения это очень много.

При использовании SPI только 2 прерывания. Или вообще без них.

Вот пример с SPI:

Настройка SPI

void Init_SPI2(void){
	/* Configure SPI pins: SCK and MOSI with default alternate function (not re-mapped) push-pull */
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_13 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	/* Configure MISO as Input with internal pull-up */
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	// SPI configuration
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; // 64000kHz/256=250kHz
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	//SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI2, &SPI_InitStructure);
	SPI_CalculateCRC(SPI2, DISABLE);
	SPI_NSSInternalSoftwareConfig(SPI2, SPI_NSSInternalSoft_Set);
	SPI_Cmd(SPI2, ENABLE);
	while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) { ; }
}

Обработка

volatile uint32_t u32ssiResult;
 uint16_t u16singleTurn;
 uint16_t u16multiTurn;
 char cBuffer[32];
volatile uint32_t u32result = 0;

uint32_t spiReadSSI( void )
{
 uint8_t u8byteCount;

 for (u8byteCount=0; u8byteCount<2; u8byteCount++)
 {
	 // отправить что-нибудь для запуска тактирования
	 SPI_I2S_SendData(SPI2, 0xffff);
	 u32result <<= 16; 
	 while( !(SPI2->SR & SPI_SR_TXE) || SPI2->SR & SPI_SR_BSY);
	 u32result |= SPI_I2S_ReceiveData(SPI2);
 }

 u32result >>= 7; // убираю часть LSBs, можно не убирать, просто у меня мусор там
 return u32result;
}
int main(void)
{
	 Init_clock();
	 Init_pins();
	 Init_SPI2();
	 Init_UART2();
	 delay_ms(50);
	 Init_IWDG(2000);
	 printf("START\r");

while(1)
    {
		delay_ms(100);
		IWDG_ReloadCounter();

		if (inc_sec++ >= 5){
			inc_sec = 0;
			u32ssiResult = spiReadSSI();
			
			u16singleTurn = u32ssiResult & 0x0000FFFF; //здесь я млачшую часть взял 2 байта
			u16multiTurn = (u32ssiResult >> 16) & 0x0000000F; //старшый, только 1 байт беру, дальше цифры уже не меняются когда линейка до краёв доходит
			//Это я разделил, чтобы по 2 байта передать по юарту
             printf( "MSB = " );
             sprintf( cBuffer, "%u ", u16multiTurn);
             printf( cBuffer );
             printf( "LSB = " );
             sprintf( cBuffer, "%u ", u16singleTurn);
             printf( cBuffer );
             printf(" \r");
		}
    }
}

Вот и всё. Схема подключения - просто через модули на MAX485. Только нужно с передающего выпаять если есть резистор на 120 ом, который параллельно A-B впаян и питать его 5 вольтами. И не забыть подать питание на выбор режима работы - передача.

Из приёмного модуля можно ничего не выпаявать, питать 3.3 вольтами, выбор режима работы подсоединить к минусу питания.

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

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

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

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

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

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

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

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

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

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

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

    • Релюхи не причём. При неисправности релюх симптомы были бы другие. И ИБП даже не клацает когда переходит в  "аварию".   Да. Аккум новый. Более того - 2 новых пробовал. И без АКБ тоже. Не влияет.
    • #include <Wire.h> #include <Oregon_TM.h> #include <BME280I2C.h> //////////////////////////////////////////////////////////////////////////////////////////////////////////// //Скетч для устройства, передающего данные датчика BME280 в формате Oregon Scientific THGN132N //Принципиальная схема прилагается. //Для работы необходима библиотека https://github.com/finitespace/BME280/ //Устройство работает от 3-ех пальчиковых батареек, для экономии электричества заливать скетч нужно через ISP //////////////////////////////////////////////////////////////////////////////////////////////////////////// //Также возможна передача данных в формате - THP (температура, влажность, давление, напряжение батареи) //Пример с приёмником поддерживает расшифоовку THP //////////////////////////////////////////////////////////////////////////////////////////////////////////// # define THGN_SEND 1 // Передавать ли данные в формате THGN132 # define THP_SEND 0 // Передавать ли данные в формате THP # define DEVICE_LOG 1 //Писать ли лог В Serial # define DONE_PIN 15 // вывод сигнала об окончании работы на таймер # define BME_WAIT 10 // Сколько мс ожидать датчик BME # define BATTERY_THR 3.5 // Порог напряжения для выставляения флага разряда батарейки (THGN) ///////////////////////////////////////////////////////////////////////////////////////////////// //Ниблы датчика THP //Во всех полях младшие ниблы идут вперёд!!! // 1-2 - тип (55) // 3 - канал (0-7) // 4-6 - (температура от -100С) * 10. Т.е. +25.1С = 1251 = 4E3h // 7-9 - Влажность *10 Т.е. 25.1% = 251 = 0FBh // 10-12 - (давление от 500ммртст) * 10. Т.е. 765мм = 2650 = A5Ah // 13-15 - данные с АЦП (A0) // 16-17 - CheckSUM // 18-19 - CRC8 (poly 0x07 start 0x00) ///////////////////////////////////////////////////////////////////////////////////////////////// Oregon_TM transmitter(4); BME280I2C bme; bool bme_present = false; float bme_temp(NAN), bme_hum(NAN), bme_pres(NAN); ///////////////////////////////////////////////////////////////////////////////////////////////// void setup() { digitalWrite(DONE_PIN, LOW); pinMode(DONE_PIN, OUTPUT); #ifdef DEVICE_LOG Serial.begin(115200); Serial.println("Waiting for BMEsensor..."); #endif //Обмен данными с BME////////////////////////////////// Wire.begin(); while(!bme.begin()) { if (millis() > BME_WAIT) break; } if (!bme.begin()) { #ifdef DEVICE_LOG Serial.println("No BME sensor found"); #endif bme_present = false; } else { switch(bme.chipModel()) { case BME280::ChipModel_BME280: bme_present = true; bme.read(bme_pres, bme_temp, bme_hum); #ifdef DEVICE_LOG Serial.println("Found BME280 sensor! Success."); Serial.print("Temperature = "); Serial.print(bme_temp, 1); Serial.println("C"); Serial.print("Humidity = "); Serial.print(bme_hum, 1); Serial.println("%"); Serial.print("Pressure = "); Serial.print(bme_pres * 0.75, 1); Serial.println("mmHg"); #endif break; default: #ifdef DEVICE_LOG Serial.println("Found UNKNOWN sensor! Error!"); #endif bme_present = false; } } //Напряжения батареи/////////////////////////////////////////// word battvotage = (word)(((float)(1.1 * 16368) / Vbg()) * 100); #ifdef DEVICE_LOG Serial.print("Battery voltage = "); Serial.println(battvotage,HEX); #endif //Подготовка и отправка данных THGN////////////////////////////////////// transmitter.protocol == 2; if (THGN_SEND) { transmitter.setType(THGN132); transmitter.setChannel(3); transmitter.setBatteryFlag(battvotage < BATTERY_THR); if (bme_present) { if (bme_hum > 98) bme_hum = 98; if (bme_hum < 2) bme_hum = 2; if (bme_temp > 70) bme_temp = 70; if (bme_temp < -50) bme_temp = -50; transmitter.setTemperature(bme_temp); transmitter.setHumidity(bme_hum); transmitter.setComfort(bme_temp, bme_hum); } else { transmitter.setTemperature(-49.9); transmitter.setHumidity(2); transmitter.setComfort(-49.9, 2); } transmitter.SendPacket(); } // Если отправляются оба формата пакетов, межу ними надо выдержать паузу if (THP_SEND && THGN_SEND) delay(100); //Подготовка и отправка данных THP////////////////////////////////////// if (THP_SEND) { transmitter.setType(THP); transmitter.setChannelTHP(1); transmitter.setBatteryTHP( battvotage); if (bme_present) { transmitter.setTemperatureTHP(bme_temp); transmitter.setHumidityTHP(bme_hum); transmitter.setPressureTHP(bme_pres * 0.75); // перевод Pa в mmHg } else { transmitter.setErrorTHP(); } transmitter.SendPacket(); } #ifdef DEVICE_LOG Serial.println(); Serial.print(millis()); Serial.println("ms"); Serial.println(); #endif //Команда на отключение питания digitalWrite(DONE_PIN, HIGH); } ///////////////////////////////////////////////////////////////////////////////////////////////// void loop(){} ///////////////////////////////////////////////////////////////////////////////////////////////// int Vbg() { ADMUX = (1<<REFS0)|(0<<REFS1)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(0<<MUX0); long buffersamp=0; for (int n=0x0; n<=0xff; n++ ) { ADCSRA = 0xc7; while (bit_is_set(ADCSRA,ADSC)); buffersamp += ADC; } buffersamp >>=4; //16368 full scale 14bit ADCSRA &= ~(1 << ADEN); // отключаем АЦП return buffersamp; } Вот код программы. Пробовал по разному и от 5в запитывал и всю систему от 3,3 в. Причем голая ардуинка с таймером работает в нормальном режиме некоторое время, но потом все равно слетает и начинает питать мк постоянно( Причем это происходит всегда через разный промежуток времени.
    • На фото может быть название , характеристики и т.д. И по этому фото я смогу выбрать такой же в инете.. самому мне не собрать..
    • А что даст фотка? Тот же щуп, только чуть крупнее и с проводами питания.
    • Для меня наверное лучше купить готовый.. цель повысить чувствительность до 1 mV.. Наверное на Авто стоит покупать , мне бы фотку какую нить..такого активного щупа..))
    • Так на схемах обозначается подключение к сети 220 В.
  • Похожий контент

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