2013-02-27 12:28 AM
Hi
I am trying to command a Pololu Maestro device from my STM32 device. The Pololu requires a non-inverted TTL signal for commands. I can send out the command through an attached UART board to a hyperterminal session on my PC but as I understand the PL 2303 on that addon board inverts the signal. I actually wanted to use the SW-attached UART-Pin as Tx signal. I tried to find a setting for the UART or Pin to be non-inverting but could not see anything like that. Can I define a Pin to be always in the inverted state of another Pin? Juerg #uart2014-09-30 06:58 PM
Funny you should say that...I am currently attempting to communicate with a $500 product that is communicating in inverted TTL. It said so in the communication specs(and verified with scope), but I never double checked since it was correctly responding to all the commands I gave it in regular UART TTL (still not sure why this is working). My STM8L doesn't seem to have the ''invert'' option (glancing at this thread, it doesn't look like the STM32 series has it either), so I'm probably going to have to bit bang it.
2014-09-30 08:15 PM
Or just add an inverter... Or an XOR gate if you want to control the polarity.
2016-02-10 04:09 AM
Nothing has happened regarding this since 2014 or did anyone think of a clever software hack? I need my STM32F407 to invert Tx and Rx because they are inverted on our PCB for application specific purposes (the UART pins will most of the time be used for other things than UART-communication). For Tx a software UART would be fine, but for Rx that wouldn't work, I would miss bytes due to processing time in between each byte. The chip in the other end is a FTDI USB-to-serial chip and I must use the standard PC-driver for that (in the Device Manager the chip MUST look like a standard COM-port). Therefore, I can't use FTDI's dll to invert the signals on the PC side.
2016-02-10 05:19 AM
With F-prog you can invert the rx/tx on the ftdi chip http://www.ftdichip.com/Support/Utilities.htm#FT_PROG.
Windows will not notice this, it's still a vcp. btw, better start your own topic.2016-02-10 05:49 AM
That's a really good idea, but unfortunately our USB-to-serial cables must be backwards compatible with our previous products.
2016-02-10 06:27 AM
That's a really good idea, but unfortunately our USB-to-serial cables must be backwards compatible with our previous products.
Yeah, so perhaps something you should have thought about in the design phase?Depending on the part/USART, you should be able to use a timer to sample the signal edges and decode the data on the Rx side.2016-02-11 08:44 AM
So, I'm trying to implement a timer-based (non-inverted to start with) UART and my transmit works fine, but my receive side isn't working properly. For every byte I receive, I also receive an extra 0xFF byte. So, for example, if I should be receiving
Testing to send a whole message then I receive T?e?s?t?i?n?g? ?t?o? ?s?e?n?d? ?a? ?w?h?o?l?e? ?m?e?s?s?a?g?e? Can anybody tell what is wrong?#define Tx_PIN GPIO_PIN_2
#define Tx_PORT GPIOA
#define SET_PIN_LOW(PORT__, PIN__) do { (PORT__->BSRR = (uint32_t)(PIN__ <<
16
)); } while (0)
#define SET_PIN_HIGH(PORT__, PIN__) do { (PORT__->BSRR = (uint32_t)(PIN__)); } while (0)
#define READ_PIN(PORT__, PIN__) (0 < (PORT__->IDR & PIN__))
#define Rx_PIN GPIO_PIN_3
#define Rx_PORT GPIOA
#define CLEAR_EXT_INT_FLAG_ON_Rx() __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3)
#define ENABLE_EXT_INT_ON_Rx() HAL_NVIC_EnableIRQ(EXTI3_IRQn)
#define DISABLE_EXT_INT_ON_Rx() HAL_NVIC_DisableIRQ(EXTI3_IRQn)
#define START_TIMER() (TIM3->CR1 |= TIM_CR1_CEN)
#define STOP_TIMER() (TIM3->CR1 &= ~TIM_CR1_CEN)
#define TIMER_INT_FLAG (TIM3->SR & 0x0001)
#define ENABLE_TIMER_INT() do { TIM3->DIER |= TIM_DIER_UIE; HAL_NVIC_EnableIRQ(TIM3_IRQn); } while (0)
#define DISABLE_TIMER_INT() do { TIM3->DIER &= ~TIM_DIER_UIE; HAL_NVIC_DisableIRQ(TIM3_IRQn); } while (0)
#define CLEAR_TIMER_INT_FLAG() (TIM3->SR &= ~TIM_SR_UIF)
#define SET_TIMER_PERIOD(period) (TIM3->ARR = period)
typedef enum
{
BAUD_115200__64_MHz = (uint32_t)(64000000/115200),
} BaudRate_t;
static uint32_t timerPeriod;
static uint32_t timerPeriodTimesOnePointFive;
void UART2_SW_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = Tx_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = 0;
HAL_GPIO_Init(Tx_PORT, &GPIO_InitStructure);
SET_PIN_HIGH(Tx_PORT, Tx_PIN);
GPIO_InitStructure.Pin = Rx_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Alternate = 0;
HAL_GPIO_Init(Rx_PORT, &GPIO_InitStructure);
TIM3->PSC = 0; // Set prescalar 1
TIM3->EGR = TIM_EGR_UG; // Generate an update event to reload the Prescaler
HAL_NVIC_EnableIRQ(CAN2_TX_IRQn); // Enable CAN bus interrupts (will be used as dummy interrupts)
ENABLE_EXT_INT_ON_Rx();
}
static void OutputBit(uint8_t bit)
{
if (0 <
bit
)
{
while (TIMER_INT_FLAG == 0) {}; // Wait until timer interrupt flag is set
SET_PIN_HIGH(Tx_PORT, Tx_PIN);
}
else
{
while (TIMER_INT_FLAG == 0) {}; // Wait until timer interrupt flag is set
SET_PIN_LOW(Tx_PORT, Tx_PIN);
}
CLEAR_TIMER_INT_FLAG();
}
void UART2_SW_SetBaudRate(BaudRate_t baudRate)
{
timerPeriod
=
baudRate
;
timerPeriodTimesOnePointFive = (3 * ((uint32_t)baudRate)) >> 1;
}
void UART2_SW_TransmitByte(uint8_t Data)
{
uint8_t i;
CLEAR_TIMER_INT_FLAG(); // Clear interrupt flag
SET_TIMER_PERIOD(UART2_BaudRate);
TIM3->CNT = (uint32_t)UART2_BaudRate - 20; // Load TIM3->CNT with HALF_PERIOD-20 to
// minimize time before 1st bit
START_TIMER();
OutputBit(0); // Start bit
for (i = 0; i <
8
; i++)
{
OutputBit((Data >> i) & 0x01);
}
OutputBit(1); // Stop bit
OutputBit(1); // Don't pack bytes to tight
STOP_TIMER();
SET_TIMER_PERIOD(0xFFFFFFFF);
}
static volatile uint8_t bitCount = 0;
static volatile uint8_t receivedByte = 0;
static volatile uint8_t finishedReceivedByte = 0;
static void resetEverything(void)
{
STOP_TIMER();
DISABLE_TIMER_INT();
CLEAR_TIMER_INT_FLAG();
SET_TIMER_PERIOD(0xFFFFFFFF);
bitCount = 0;
CLEAR_EXT_INT_FLAG_ON_Rx();
ENABLE_EXT_INT_ON_Rx();
}
void TIM3_IRQHandler(void)
{
static uint8_t sampledValue;
sampledValue = READ_PIN(Rx_PORT, Rx_PIN);
CLEAR_TIMER_INT_FLAG();
if (bitCount == 0)
{
SET_TIMER_PERIOD(timerPeriod);
receivedByte = sampledValue;
bitCount++;
}
else if ((1 <= bitCount) && (bitCount <= 6))
{
receivedByte |= (sampledValue <<
bitCount
);
bitCount++;
}
else if (bitCount == 7)
{
finishedReceivedByte
=
receivedByte
| (sampledValue << 7);
resetEverything();
NVIC->STIR = CAN2_TX_IRQn; // Create a dummy interrupt that will call the callback
}
else
{
resetEverything();
}
}
void CAN2_TX_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(CAN2_TX_IRQn);
UART4_TransmitByte(finishedReceivedByte);
}
void EXTI3_IRQHandler(void)
{
START_TIMER();
SET_TIMER_PERIOD(timerPeriodTimesOnePointFive);
CLEAR_TIMER_INT_FLAG();
ENABLE_TIMER_INT();
DISABLE_EXT_INT_ON_Rx();
bitCount = 0;
CLEAR_EXT_INT_FLAG_ON_Rx();
}
2016-02-12 01:42 AM
I have found the my external interrupt is triggered twice for some strange reason, that is why I'm receiving two bytes. In the first interrupt, EXTI->PR = 0x00000008 and in the second interrupt EXTI->PR = 0.
2016-02-12 02:22 AM
The last instruction (EXTI PR clearing) of the IRQ handler is not completed before the Cortex-M3 exit from interrupt ... and re-enters because of EXTI PR not being cleared (yet). In the mean time before the second execution of the handler, EXTI PR had time to be cleared.
The clever solution is to read EXTI PR as the last IRQ handler statement.2016-02-12 03:28 AM
You mean I should put
while (EXTI->PR != 0) {}; in the end ofEXTI3_IRQHandler? That didn't solve the problem. I can do the following, but preferably I would like to avoid the second interrupt altogether:void EXTI3_IRQHandler(void)
{
TIM3->CNT = 0;
START_TIMER();
if ((EXTI->PR & 0x00000008) == 0)
{
resetEverything();
return;
}
SET_TIMER_PERIOD(timerPeriodTimesOnePointFive);
CLEAR_TIMER_INT_FLAG();
ENABLE_TIMER_INT();
bitCount = 0;
DISABLE_EXT_INT_ON_Rx();
CLEAR_EXT_INT_FLAG_ON_Rx();
}