Stm32 + 1-wire + DMA (продолжение)

Это продолжение статьи Stm32 + 1-wire + DMA. Обещал собрать все в библиотечку — вот и она.


Решил сделать как советовал Vga — буфер в памяти будет 8 байт. Этого хватит на отправку/прием одного байта через 1-wire.

Соответственно, в библиотеке будут две функции — инициализация и отправка/прием:

//-----------------------------------------------------------------------------
// осуществляет сброс и проверку на наличие устройств на шине
//-----------------------------------------------------------------------------
uint8_t OW_Reset();

//-----------------------------------------------------------------------------
// процедура общения с шиной 1-wire
// sendReset - посылать RESET в начале общения.
// 		OW_SEND_RESET или OW_NO_RESET
// command - массив байт, отсылаемых в шину. Если нужно чтение - отправляем OW_READ_SLOT
// cLen - длина буфера команд, столько байт отошлется в шину
// data - если требуется чтение, то ссылка на буфер для чтения
// dLen - длина буфера для чтения. Прочитается не более этой длины
// readStart - с какого символа передачи начинать чтение (нумеруются с 0)
//		можно указать OW_NO_READ, тогда можно не задавать data и dLen
//-----------------------------------------------------------------------------
uint8_t OW_Send(uint8_t sendReset, uint8_t *command, uint8_t cLen,
		uint8_t *data, uint8_t dLen, uint8_t readStart);


С инициализацией вроде все понятно. Если будет использоваться процессор не stm32f103, то проверить соответствие инициализируемых ножек и каналов DMA выбранному USART.

Проинициализировались, теперь работа с шиной. По идее, каждый цикл общения с устройствами начинается с Reset. Но на всякий случай эту возможность сделал опциональной — первый параметр функции OW_Send() как раз и отвечает за посылку Reset.

Дальше идет указатель на массив байт — данные, которые будут передаваться в шину 1-wire. Массив может находиться во флеш-области, перезаписываться он не будет. Если подразумевается чтение, то соответствующие слоты должны быть заполнены байтами OW_READ_SLOT (0xff). Ну и количество байт тоже передается через параметр cLen.

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

Последний параметр — с какого байта посылки надо начинать чтение. Байты нумеруются с нуля. Если указать значение OW_NO_READ, то чтение не подразумевается.

В файле onewire.h есть параметр OW_GIVE_TICK_RTOS — в этом случае в циклах ожидания будет отдаваться тик для FreeRTOS. Это чтобы не заморачиваться с прерываниями.

Вот пример использования:


	OW_Init();

	OW_Send(OW_SEND_RESET, "\xcc\x44", 2, NULL, NULL, OW_NO_READ);

	for (i=0; i<1000000; i++);

	uint8_t buf[2];
	OW_Send(OW_SEND_RESET, "\xcc\xbe\xff\xff", 4, buf,2, 2);


Ну и архив прикрепляю, пробуйте.

  • +2
  • 13 февраля 2012, 15:30
  • steel_ne
  • 1
Файлы в топике: onewire102.zip

Комментарии (16)

RSS свернуть / развернуть
OW_READ_SLOTH
SLOT же.

А в остальном одобряю.
0
  • avatar
  • Vga
  • 13 февраля 2012, 17:58
Поправил. По смыслу интересно получалось ))
0
Privet
zacem v resete goniat dva raza polnuju strukturu? Poskolku eto biblioteka, kotoruju nebudim citat kazdij denj, mozno napeiamuju sdelat zapis v registr 9600 — OW_USART->BRR = (uint32_t)0x00000EA6;, a 115200 — OW_USART->BRR = (uint32_t)0x00000138;
Eto na 72Mhz, mozno dopolnit degainom s deleniem ot taktovoi
0
а будет продолжение до полноценного термометра?)))
0
Спасибо за библиотеку. Все вроде пашет. Единственное отладчик вываливается в assert_failed на строке
USART_ClearFlag(OW_USART, USART_FLAG_RXNE | USART_FLAG_TC | USART_FLAG_TXE);
USART_FLAG_TXE типа нельзя сбросить.
0
Ошибочка, на первом порте не заработает…
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);
0
  • avatar
  • wiha
  • 11 января 2013, 01:27
В коде библиотеки есть:

		// Ждем, пока не примем 8 байт
		while (DMA_GetFlagStatus(OW_DMA_FLAG) == RESET){
#ifdef OW_GIVE_TICK_RTOS
			taskYIELD();
#endif
		}


Вот эта конструкция может повлечь беду. Если датчик отвалится, то здесь бесконечный цикл получится. Отдавай тик, не отдавай, а текущая задача заблокирована.
0
Что то у меня не правильный результат. результат T1 =41, T2 = 155 грею ничего не меняется

  OW_Init();
  N=OW_Scan(addr[0],2);
  _DBG(FULL, " N = 2%i\n", N); // находит два датчика все верно 
  while (1)
  {
    OW_Send(OW_SEND_RESET, "\xcc\x44", 2, NULL, NULL, OW_NO_READ);
    for (u32 i=0; i<1000000; i++);
    
    OW_Send(OW_SEND_RESET, "\x55\x28\x91\xF2\xF4\x04\x00\x00\x5C\xbe\xff\xff", 4, temprbuff,2, 2);
    T1 = convT_DS18B20(temprbuff[0], temprbuff[1]);
    
    OW_Send(OW_SEND_RESET, "\x55\x28\xBA\x99\xF5\x04\x00\x00\xFC\xbe\xff\xff", 4, temprbuff,2, 2);
    T2 = convT_DS18B20(temprbuff[0], temprbuff[1]);
    _DBG(FULL, " T1 =%i, T2 = %i\n", T1,  T2);
  }

  u8 convT_DS18B20(u8 LSB, u8 MSB)
  {
   LSB >>= 4; // убираем дробную часть
   MSB <<= 4; // убираем лишние знаки
   return(MSB | LSB); // объединяем 2 байта -> возврат
  }


Вот так все работает хорошо (один датчик).

    OW_Send(OW_SEND_RESET, "\xcc\x44", 2, NULL, NULL, OW_NO_READ);
    for (u32 i=0; i<1000000; i++);
    OW_Send(OW_SEND_RESET, "\xcc\xbe\xff\xff", 4, tempr,2, 2);


Пробовал один датчик по адресу тоже ничего меняется, не верный результат. схема вкл. 3 провода.
0
  • avatar
  • VIC
  • 28 декабря 2013, 03:26
Опечатка там 12 байт.
OW_Send(OW_SEND_RESET, "\x55\x28\x91\xF2\xF4\x04\x00\x00\x5C\xbe\xff\xff", 12, temprbuff,2, 2);
0
От таких опечаток здорово спасает использование констант и sizeof(). Только массивы байт нужно писать именно как массивы байт, а не как строки.
0
OW_Send(OW_SEND_RESET, "\x55\x28\xBA\x99\xF5\x04\x00\x00\xFC\xbe\xff\xff", 12, temprbuff,2, 10); вот так правильно.
Вот тут нужно поправить
0
у меня плата stm32F407discovery. Настроил уарт на работу на 9бит (если 9 бит 1 адресс, 0 даные, все работает. Использую DMA даные идут, но не те что мне нужно.

В двух случаях передаю масив const uint16_t TestPacket2[4] = {(200 | 0x100) ,1,2,3 };

void prvSendData( void *pvParameters )
{
for(;;)
{
SendPacketToSlave (TestPacket2, 4);
vTaskDelay(1000);
}
}

void SendPacketToSlave(const uint16_t* buffer, uint16_t size)
{
DMA_InitTypeDef DMA_InitSt;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

DMA_InitTypeDef DMA_InitSt;
DMA_DeInit(DMA2_Stream7);
DMA_InitSt.DMA_Channel = DMA_Channel_4;
DMA_InitSt.DMA_PeripheralBaseAddr = (uint32_t) &(USART1->DR);
DMA_InitSt.DMA_Memory0BaseAddr = (uint32_t) &buffer;
DMA_InitSt.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitSt.DMA_BufferSize = size;
DMA_InitSt.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitSt.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitSt.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitSt.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitSt.DMA_Mode = DMA_Mode_Normal;
DMA_InitSt.DMA_Priority = DMA_Priority_Medium;
DMA_InitSt.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitSt.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitSt.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream7, &DMA_InitSt);

USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

DMA_Cmd(DMA2_Stream7, ENABLE);
}
должно передаться так адрес: 200, 1, 2, 3
а получаеться так как на картинке
Не могу понять в чём проблемма.
0
  • avatar
  • Nemo
  • 01 марта 2015, 02:24
Спасибо за библиотеку. В библиотеке есть ошибка: в разделе «DMA на чтение» и «DMA на чтение» в строке
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR); «USART2» прописан hard кодом,
в результате если использовать USART1 — надо править эту строчку или немного доработать библиотеку. КСпасибо за статьи. Заработало сразу.
0
для исправления нужно просто заменить строки
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR); на
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(OW_USART->DR);
0
Висну в OW_Reset() в ожидании флага USART_FLAG_TC — что это может означать?
Если комментирую цикл ожидания, получаю ow_presence=0x01. Двухпроводная схема с диодом [stm32F411RET6 on NucleoF411RE]
uint8_t OW_Reset()
{
volatile uint8_t 			ow_presence=2,tmp;
volatile	uint32_t	j;
USART_InitTypeDef 	USART_Init_OW;
	
	//set 9600, send byte 0xf0, wait for sending, read bus, if=0xf0 = none dev, set 115200
	USART_DMACmd(USART2, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE);	
	USART_Init_OW.USART_BaudRate = 9600;
	USART_Init_OW.USART_WordLength = USART_WordLength_8b;
	USART_Init_OW.USART_StopBits = USART_StopBits_1;
	USART_Init_OW.USART_Parity = USART_Parity_No;
	USART_Init_OW.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init_OW.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_Init(USART2, &USART_Init_OW);
	
	USART_ClearFlag(USART2, USART_FLAG_TC);//??? íàäî ëè	
//	NVIC_EnableIRQ(USART2_IRQn);	
//	USART_ITConfig(USART2, USART_IT_TC, ENABLE);
//	USART_Cmd(USART2, ENABLE);
	
	USART_SendData(USART2, Search_ROM);
	while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)	
		{}		////original =tick to RTOS=Transfer Complete;!!here is loop w/o end
	ow_presence = USART_ReceiveData(USART2);
		
	USART_Init_OW.USART_BaudRate = 115200;
	USART_Init_OW.USART_WordLength = USART_WordLength_8b;
0
Sorry, не могу найти как отредактировать — очепятки прошли: 1) строка USART_Cmd(USART2, ENABLE); активна и 2) ответ ow_presence = 0x00
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.