/********************************* (C) РОТЕК *********************************** * @module onewire * @file onewire.c * @version 1.0.0 * @date XX.XX.XXXX * $brief DS18B20 temperature sensor driver ******************************************************************************* * @history Version Author Comment * XX.XX.XXXX 1.0.0 Telenkov D.A. First release. ******************************************************************************* */ #include "common_config.h" #include "stm32f4xx.h" #include "stm32f4xx_dma.h" #include "usart.h" #include "gpio.h" #include "onewire.h" #ifdef PRINTF_STDLIB #include #endif #ifdef PRINTF_CUSTOM #include "tinystdio.h" #endif /* Force remove debug output */ #undef DBG #define DBG if(0) #ifdef DALLAS_SENSOR_ENABLE /** * @brief Размер буфера для отправки данных датчикам */ #define DALLAS_BUF_SIZE 8 #define DALLAS_TIME_OUT 1500000 #define DALLAS_0 0x00 #define DALLAS_1 0xff #define DALLAS_R_1 0xff typedef struct { gpio_t ow_pin; USART_TypeDef *uart_addr; DMA_InitTypeDef DMA_InitStructureTx; DMA_InitTypeDef DMA_InitStructureRx; uint8_t sensorBuf[DALLAS_BUF_SIZE]; }ow_sensor_t; ow_sensor_t ow_sensor[MAX_T_SENSORS]; #define T_SENSOR_ADD(sensor_num, ow_line, uart) \ do { \ ow_sensor[sensor_num].uart_addr = uart; \ ow_sensor[sensor_num].ow_pin = ow_line; \ } while (0); /** * @brief Настройка USART * @retval */ void DALLAS_Init() { #define XTSENSOR(sensor_num, ow_line, uart) T_SENSOR_ADD(sensor_num, ow_line, uart); T_SENSOR_TABLE #undef XTSENSOR for (uint8_t i = 0; i < MAX_T_SENSORS; i ++) { uart_hw_init(ow_sensor[i].uart_addr, DALLAS_SENSOR_UART_BAUD, DALLAS_SENSOR_UART_WORD_LEN, DALLAS_SENSOR_UART_PARITY, DALLAS_SENSOR_UART_STOP_BIT); } DALLAS_DmaInit(); } /** * @brief Настройка DMA * @retval */ void DALLAS_DmaInit(void) { DMA_Stream_TypeDef *RxDMA_Stream = NULL; DMA_Stream_TypeDef *TxDMA_Stream = NULL; uint32_t RxDMA_Channel = 0; uint32_t TxDMA_Channel = 0; for (uint8_t i = 0; i < MAX_T_SENSORS; i ++) { if (ow_sensor[i].uart_addr == USART1) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); RxDMA_Stream = DMA1_Stream2; TxDMA_Stream = DMA1_Stream7; RxDMA_Channel = DMA_Channel_4; TxDMA_Channel = DMA_Channel_4; } else if (ow_sensor[i].uart_addr == USART2) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); RxDMA_Stream = DMA1_Stream5; TxDMA_Stream = DMA1_Stream6; RxDMA_Channel = DMA_Channel_4; TxDMA_Channel = DMA_Channel_4; } else if (ow_sensor[i].uart_addr == USART3) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); RxDMA_Stream = DMA1_Stream1; TxDMA_Stream = DMA1_Stream3; RxDMA_Channel = DMA_Channel_4; TxDMA_Channel = DMA_Channel_4; } else if (ow_sensor[i].uart_addr == UART4) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); RxDMA_Stream = DMA1_Stream2; TxDMA_Stream = DMA1_Stream4; RxDMA_Channel = DMA_Channel_4; TxDMA_Channel = DMA_Channel_4; } else if (ow_sensor[i].uart_addr == UART5) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); RxDMA_Stream = DMA1_Stream0; TxDMA_Stream = DMA1_Stream7; RxDMA_Channel = DMA_Channel_4; TxDMA_Channel = DMA_Channel_4; } else if (ow_sensor[i].uart_addr == USART6) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); RxDMA_Stream = DMA2_Stream1; TxDMA_Stream = DMA2_Stream6; RxDMA_Channel = DMA_Channel_5; TxDMA_Channel = DMA_Channel_5; } /* DMA на чтение */ DMA_DeInit(RxDMA_Stream); ow_sensor[i].DMA_InitStructureRx.DMA_Channel = RxDMA_Channel; ow_sensor[i].DMA_InitStructureRx.DMA_PeripheralBaseAddr = (uint32_t)&ow_sensor[i].uart_addr->DR; ow_sensor[i].DMA_InitStructureRx.DMA_Memory0BaseAddr = (uint32_t)&ow_sensor[i].sensorBuf; ow_sensor[i].DMA_InitStructureRx.DMA_DIR = DMA_DIR_PeripheralToMemory; ow_sensor[i].DMA_InitStructureRx.DMA_BufferSize = DALLAS_BUF_SIZE; ow_sensor[i].DMA_InitStructureRx.DMA_PeripheralInc = DMA_PeripheralInc_Disable; ow_sensor[i].DMA_InitStructureRx.DMA_MemoryInc = DMA_MemoryInc_Enable; ow_sensor[i].DMA_InitStructureRx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; ow_sensor[i].DMA_InitStructureRx.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; ow_sensor[i].DMA_InitStructureRx.DMA_Mode = DMA_Mode_Normal; ow_sensor[i].DMA_InitStructureRx.DMA_Priority = DMA_Priority_Medium; DMA_Init(RxDMA_Stream, &ow_sensor[i].DMA_InitStructureRx); /* DMA на запись */ DMA_DeInit(TxDMA_Stream); ow_sensor[i].DMA_InitStructureTx.DMA_Channel = TxDMA_Channel; ow_sensor[i].DMA_InitStructureTx.DMA_PeripheralBaseAddr = &ow_sensor[i].uart_addr->DR; ow_sensor[i].DMA_InitStructureTx.DMA_Memory0BaseAddr = (uint32_t)&ow_sensor[i].sensorBuf; ow_sensor[i].DMA_InitStructureTx.DMA_DIR = DMA_DIR_MemoryToPeripheral; ow_sensor[i].DMA_InitStructureTx.DMA_BufferSize = DALLAS_BUF_SIZE; ow_sensor[i].DMA_InitStructureTx.DMA_PeripheralInc = DMA_PeripheralInc_Disable; ow_sensor[i].DMA_InitStructureTx.DMA_MemoryInc = DMA_MemoryInc_Enable; ow_sensor[i].DMA_InitStructureTx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; ow_sensor[i].DMA_InitStructureTx.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; ow_sensor[i].DMA_InitStructureTx.DMA_Mode = DMA_Mode_Normal; ow_sensor[i].DMA_InitStructureTx.DMA_Priority = DMA_Priority_Medium; DMA_Init(TxDMA_Stream, &ow_sensor[i].DMA_InitStructureTx); } } /** * @brief Настроить TX пин как питающий выход * @retval */ void DALLAS_OutSetAsPower(t_sensor_list_t sensor) { gpio_pindef_t *pin = &gpio_pins[ow_sensor[sensor].ow_pin]; gpio_hw_config_pin(pin->port, pin->pin, (GPIO_MODE_OUT_CFG | GPIO_TYPE_PP_CFG | GPIO_SPEED_HIGH_CFG)); gpio_set(ow_sensor[sensor].ow_pin, GPIO_SET); } /** * @brief Настроить TX пин как передатчик * @retval */ void DALLAS_OutSetAsTX(t_sensor_list_t sensor) { gpio_pindef_t *pin = &gpio_pins[ow_sensor[sensor].ow_pin]; uint8_t af_n = (uint8_t)(pin->flags >> _GPIO_AF_SHIFT); gpio_connect_af(ow_sensor[sensor].ow_pin, af_n); gpio_hw_config_pin(pin->port, pin->pin, GPIO_MODE_AF_CFG | GPIO_SPEED_HIGH_CFG); } /** * @brief Сброс и проверка наличия устройства на шине 1-wire * @retval */ uint8_t DALLAS_SensorReset(t_sensor_list_t sensor) { uint8_t presence; uart_config_reinit(ow_sensor[sensor].uart_addr, DALLAS_SENSOR_RST_UART_BAUD, DALLAS_SENSOR_UART_WORD_LEN, DALLAS_SENSOR_UART_PARITY, DALLAS_SENSOR_UART_STOP_BIT); // отправляем 0xf0 на скорости 9600 USART_ClearFlag(ow_sensor[sensor].uart_addr, USART_FLAG_TC); USART_SendData(ow_sensor[sensor].uart_addr, 0xf0); while (USART_GetFlagStatus(ow_sensor[sensor].uart_addr, USART_FLAG_TC) == RESET) { } presence = USART_ReceiveData(ow_sensor[sensor].uart_addr); uart_config_reinit(ow_sensor[sensor].uart_addr, DALLAS_SENSOR_UART_BAUD, DALLAS_SENSOR_UART_WORD_LEN, DALLAS_SENSOR_UART_PARITY, DALLAS_SENSOR_UART_STOP_BIT); if (presence != 0xf0) { DBG printf("DALLAS_SensorReset: DALLAS_OK\r\n"); return DALLAS_OK; } DBG printf("DALLAS_SensorReset: DALLAS_NO_DEVICE\r\n"); return DALLAS_NO_DEVICE; } /** * @brief Отправка и прием данных * @param sendReset посылать RESET в начале общения. * OW_SEND_RESET * OW_NO_RESET * @param *command - массив байт, отсылаемых в шину. * Если нужно чтение - отправляем OW_READ_SLOTH * @param cLen - длина буфера команд, столько байт отошлется в шину * @param *data - если требуется чтение, то ссылка на буфер для чтения * @param dLen - длина буфера для чтения. Прочитается не более этой длины * @param readStart - с какого символа передачи начинать чтение (нумеруются с 0) * можно указать OW_NO_READ, тогда можно не задавать data и dLen * @retval */ uint8_t DALLAS_Send(t_sensor_list_t sensor, uint8_t sendReset, uint8_t *command, uint8_t cLen, uint8_t *data, uint8_t dLen, uint8_t readStart) { uint32_t timeOutCounter = 0; uint32_t DMA_FLAG_TCIF = 0; DMA_Stream_TypeDef *RxDMA_Stream = NULL; DMA_Stream_TypeDef *TxDMA_Stream = NULL; if (ow_sensor[sensor].uart_addr == USART1) { DMA_FLAG_TCIF = DMA_FLAG_TCIF2; RxDMA_Stream = DMA1_Stream2; TxDMA_Stream = DMA1_Stream7; } else if (ow_sensor[sensor].uart_addr == USART2) { DMA_FLAG_TCIF = DMA_FLAG_TCIF5; RxDMA_Stream = DMA1_Stream5; TxDMA_Stream = DMA1_Stream6; } else if (ow_sensor[sensor].uart_addr == USART3) { DMA_FLAG_TCIF = DMA_FLAG_TCIF1; RxDMA_Stream = DMA1_Stream1; TxDMA_Stream = DMA1_Stream3; } else if (ow_sensor[sensor].uart_addr == UART4) { DMA_FLAG_TCIF = DMA_FLAG_TCIF2; RxDMA_Stream = DMA1_Stream2; TxDMA_Stream = DMA1_Stream4; } else if (ow_sensor[sensor].uart_addr == UART5) { DMA_FLAG_TCIF = DMA_FLAG_TCIF0; RxDMA_Stream = DMA1_Stream0; TxDMA_Stream = DMA1_Stream7; } else if (ow_sensor[sensor].uart_addr == USART6) { DMA_FLAG_TCIF = DMA_FLAG_TCIF1; RxDMA_Stream = DMA2_Stream1; TxDMA_Stream = DMA2_Stream6; } /* если требуется сброс - сбрасываем и проверяем на наличие устройств */ if (sendReset == DALLAS_SEND_RESET) { DBG printf("_Send: DALLAS_SEND_RESET\r\n"); if (DALLAS_SensorReset(sensor) == DALLAS_NO_DEVICE) { DBG printf("_Send: DALLAS_NO_DEVICE\r\n"); return DALLAS_NO_DEVICE; } } while (cLen > 0) { DALLAS_ToBits(*command, ow_sensor[sensor].sensorBuf); command++; cLen--; /* DMA на чтение */ DMA_DeInit(RxDMA_Stream); DMA_Init(RxDMA_Stream, &ow_sensor[sensor].DMA_InitStructureRx); /* DMA на запись */ DMA_DeInit(TxDMA_Stream); DMA_Init(TxDMA_Stream, &ow_sensor[sensor].DMA_InitStructureTx); /* старт цикла отправки */ USART_ClearFlag(ow_sensor[sensor].uart_addr, USART_FLAG_RXNE | USART_FLAG_TC ); USART_DMACmd(ow_sensor[sensor].uart_addr, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE); DMA_Cmd(RxDMA_Stream, ENABLE); DMA_Cmd(TxDMA_Stream, ENABLE); while (DMA_GetFlagStatus(RxDMA_Stream, DMA_FLAG_TCIF) == RESET) { timeOutCounter++; if (timeOutCounter > DALLAS_TIME_OUT) { DBG printf("_Send: return DALLAS_ERROR\r\n"); return DALLAS_ERROR; } } DBG printf("timeOutCounter: %u\r\n", (unsigned int)timeOutCounter); /* отключаем DMA */ DMA_Cmd(RxDMA_Stream, DISABLE); DMA_Cmd(TxDMA_Stream, DISABLE); USART_DMACmd(ow_sensor[sensor].uart_addr, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE); /* если прочитанные данные кому-то нужны - выкинем их в буфер */ DBG printf("_Send: readStart = %d, dLen = %d\r\n", readStart, dLen); if (readStart == 0 && dLen > 0) { *data = DALLAS_ToByte(ow_sensor[sensor].sensorBuf); data++; dLen--; DBG printf("_Send: Copy\r\n"); } else { if (readStart != DALLAS_NO_READ) { readStart--; DBG printf("_Send: readStart--\r\n"); } DBG printf("_Send: else state\r\n"); } } DBG printf("_Send: return DALLAS_OK\r\n"); return DALLAS_OK; } /** * @brief Функция преобразует один байт в восемь, для передачи через USART * @param ow_byte - байт, который надо преобразовать * @param ow_bits - ссылка на буфер, размером не менее 8 байт * @retval */ void DALLAS_ToBits(uint8_t ow_byte, uint8_t *ow_bits) { uint8_t i; for (i = 0; i < 8; i++) { if (ow_byte & 0x01) { *ow_bits = DALLAS_1; } else { *ow_bits = DALLAS_0; } ow_bits++; ow_byte = ow_byte >> 1; } } /** * @brief Обратное преобразование - из того, что получено через USART опять собирается байт * @param ow_bits - ссылка на буфер, размером не менее 8 байт * @param ow_byte - собранный байт данных * @retval */ uint8_t DALLAS_ToByte(uint8_t *ow_bits) { uint8_t ow_byte, i; ow_byte = 0; for (i = 0; i < 8; i++) { ow_byte = ow_byte >> 1; if (*ow_bits == DALLAS_R_1) { ow_byte |= 0x80; } ow_bits++; } return ow_byte; } #endif