AnsweredAssumed Answered

Why USART transmission depends on function calls order?

Question asked by plehotko.gleb on Jul 23, 2014
Latest reply on Jul 24, 2014 by plehotko.gleb
     Hello, please help me to solve next problem. I have application, which consists of three main modules: io_init(), lcd_init() and usart_init() —  io_init() configures button inputs and some outputs used for relays driving and indication; lcd_init() initializes HD44780-based lcd; and usart_init() configures USART, which is used to communicate with external equipment using MODBUS protocol.
     The problem is next: if I run this routines sequentially, for example io_init() — lcd_init() — usart_init(), then I can't send anything using USART. At the same time debugging shows, that everything is all right — program operates in required sequience and USART settings are Ok — APB clock is enabled, UE and TE bits in USART CR1 register are set to 1. Next, if I comment, for example lcd_init() call, then transmission starts and packet is sent. If I comment both lcd_init() and io_init(), then transmission fails again — settings are Ok, but when application writes first byte — nothing happens again. If I uncomment everything and change order of execution to io_init(), usart_init(), lcd_init() USART operates normally.  And one more. If i comment function calls from lcd_init() everything is Ok again.
     I used disassmbler, but it doesn't show nothing suspicious. Please, help me to understand, what is wrong in my routines, because final version of this firmware may call this routines in random order. I'm using STM32F100C6 and IAR ARM.
     Here is source:


void main(void)
{
  SystemInit();         // System clock configuration
 
  io_init();
  lcd_init();
  usart_init();


  __enable_interrupt();


  read_holding_registers(16, 5, 4);


  while(1);
}




#define USART_PORT_APB_ENABLE   RCC_APB2Periph_GPIOA
#define USART_APB_ENABLE               RCC_APB1Periph_USART2
#define RxTx_PORT_ENABLE                 RCC_APB2Periph_GPIOA


void usart_init(void)
{
USART_InitTypeDef               UsartInitStruct;
NVIC_InitTypeDef                InterruptInitStruct;




  // USART Rx and Tx pins setup
  RCC_APB2PeriphClockCmd(USART_PORT_APB_ENABLE, ENABLE);  // Turn corresponding PORT clocking
  
  RxTx_PORT->CRL&=~( (uint32_t) ( 0x0F<<(TX_PIN*4) ) );   // Clear Tx Pin configuration
  RxTx_PORT->CRL|=0x09<<(TX_PIN*4);                                // Alternate function push-pull, 10 MHz max speed




  RxTx_PORT->CRL&=~( (uint32_t) ( 0x0F<<(RX_PIN*4) ) );  // Clear Rx Pin configuration
  RxTx_PORT->CRL|=0x04<<(RX_PIN*4);                               // Floating input


  RCC_APB1PeriphClockCmd(USART_APB_ENABLE, ENABLE);  // Enable USART clocking


  UsartInitStruct.USART_Mode=USART_Mode_Tx;
  UsartInitStruct.USART_BaudRate=USART_BAUD_RATE;  
  UsartInitStruct.USART_WordLength=USART_WordLength_9b;
  UsartInitStruct.USART_Parity=USART_Parity_No;
  UsartInitStruct.USART_StopBits=USART_StopBits_2;
  
  USART_Init(USART, &UsartInitStruct);
  USART_Cmd(USART,ENABLE);                                      // Turn on USART
  
  InterruptInitStruct.NVIC_IRQChannel=USART_NVIC_IRQ;
  InterruptInitStruct.NVIC_IRQChannelSubPriority=0;
  InterruptInitStruct.NVIC_IRQChannelPreemptionPriority=0;
  InterruptInitStruct.NVIC_IRQChannelCmd=ENABLE;
  NVIC_Init(&InterruptInitStruct);                              // Enable USART interruprts
  
  /* Configuring Rx/Tx switch, because USART operates
     in half-duplex mode using RS-485 */
  RCC_APB2PeriphClockCmd(RxTx_PORT_ENABLE, ENABLE);             // Enable port clock
  RxTx_PORT->CRL&=~( (uint32_t) (0x0F<<(RX_TX_SWITCH_PIN*4)));  
  RxTx_PORT->CRL|=0x02<<(RX_TX_SWITCH_PIN*4);            // General purpose push-pull, 2 Mhz max speed


  adu=calloc(MAX_ADU_SIZE, sizeof(uint8_t));                               // Allocate memory for USART buffer
}


void lcd_init(void)
{
  set_bus_to_output();  // Configuring pins, connecte to LCD
  
  CLEAR_RS;
  CLEAR_RW;
  SET_E;
  
  // Other LCD initialization instructions are not shown
}


void io_init(void)
{
GPIO_InitTypeDef        PortInitStruct;


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE);


  // PA0 — discrete input; PA9-PA12 — buttons;
  PortInitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
  PortInitStruct.GPIO_Speed=GPIO_Speed_2MHz;
  PortInitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &PortInitStruct);


  // PA8 — discrete output;  
  PortInitStruct.GPIO_Pin=GPIO_Pin_8;
  PortInitStruct.GPIO_Speed=GPIO_Speed_2MHz;
  PortInitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &PortInitStruct);


  // PC14 и PC15 — relays
  PortInitStruct.GPIO_Pin=GPIO_Pin_14|GPIO_Pin_15;
  PortInitStruct.GPIO_Speed=GPIO_Speed_2MHz;
  PortInitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
  GPIO_Init(GPIOC, &PortInitStruct);
}


void read_holding_registers(uint8_t slave_address, uint16_t start_address, uint16_t quantity)
{
  if (!(modbus_status&REQUEST_IN_PROCESS))
  {
    adu[0]=slave_address;
    adu[1]=0x03;
    adu[2]=start_address>>8;
    adu[3]=start_address;
    adu[4]=quantity>>8;
    adu[5]=quantity;
    send_adu(6);
  }
}


void send_adu(uint8_t bytes_num)
{
uint16_t        temp;


  TRANSMITTER_ON;


  temp=modbus_crc(bytes_num);
  *(adu+bytes_num)=temp;
  *(adu+(bytes_num+1))=temp>>8;


  bytes_num+=2;
  bytes_to_send=bytes_num;


  USART->DR=adu[0];
  USART->CR1|=USART_CR1_TXEIE; // Other bytes must be sent in ISR
  
  usart_byte=1;
}


Sorry for poor English, and thanks for help.

Outcomes