Monday, 17 July 2017

STM32F103C8T6

20170727.4

Items:
1  PC    (Windows 7)
2  Internet access
3  ST-Link V2    US$ 2.57         
4  STM32F103C8T6 Minimum System Development Board    US$ 2.15    

5  IDE    (Keil MDK523)
6  Breadboard, connectors, LEDs, resistors etc
7  74HC164
8  LCD 1602

Setup:
Read STM32F103xx Reference Manual
Read STM32F103x8 Datasheet
Download The-Generic-STM32F103-Pinout-Diagram
Install IDE including the STM32F100 pack and the ST-Link V2 driver
Connect the STM32F103 to the ST-LinkV2
Plug the ST-LinkV2 to the PC

Programming:
Launch the IDE
Create a new uVision project with STM32F103C8 as the device,
     and include the CMSIS CORE and the Device Startup.
In "Options for Target", use ST-Link Debugger with 'SW' setting.
Type in a program, name it main.c and add it to the project
Rebuild and (Click Start/Stop) Debug (Session)
(Click) Run and check that the STM32F103 behaves as in the program.    

Approach:
IDE usage and downloading
Simple output
Interrupt
SPI output
Clock and timing
LCD 1602  next...

Notes on the Examples:
T10.c          Just to test program compilation and downloading.
T11.c          Turn on the LED on the board.
T15.c          Blink the LED.
T16.c          Brightness control, just for fun. Not useful.
T21.c          Test interrupt programming.
T32.c          SPI1 Output to 74HC164
T40.c          Check clock source
T42.c          Select HSI, 1-second interval
T43.c          HSI with PLL --> 16 MHz
T44.c          HSI with PLL --> 64 MHz
T46.c          Select HSE (8-MHz)
T47.c          HSE with PLL --> 72 MHz

Examples:
==========
//  T10.c

int main(void){

    while(1);
}

==========
//  T11.c

#include <stm32f10x.h>

int main(void){

    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

    while(1){}
}

==========
//  T15.c

#include <stm32f10x.h>

int main(void){
    int i,j ;
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

    while(1){
        GPIOC->ODR    &=     ~(1<<13) ;  
        for(i=0;i<=1000;i++){for(j=0;j<=1000;j++);}  // Software delay
        GPIOC->ODR    |=     (1<<13) ;  
        for(i=0;i<=1000;i++){for(j=0;j<=1000;j++);}  // Software delay
    }
   
    //while(1){}
}

==========
//  T16.c

#include <stm32f10x.h>

int main(void){
    int i,j ;
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

    while(1){
    for(j=10;j<4990;j++){
            GPIOC->ODR    &=     ~(1<<13) ;
            for(i=0;i<j;i++);         // ON delay
            GPIOC->ODR    |=     (1<<13) ;  
            for(i=0;i<(5000-j);i++);  // Off delay
        }
    }
   
    //while(1){}
}

==========
//  T21.c

#include <stm32f10x.h>

int i ;

int main(void){
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

    RCC->APB1ENR    |=     RCC_APB1ENR_TIM2EN ;
    TIM2->PSC = 999 ;                            // 1000
  //TIM2->ARR = 999 ;                    
  TIM2->CR1     |= TIM_CR1_CEN ;                 // Enable Timer
  TIM2->SR      &= ~TIM_SR_UIF;           // Clear Timer Flag
  TIM2->DIER    |= TIM_DIER_UIE ;                // Enable Timer Interrupt

    NVIC->ISER[0]    |= 1<<TIM2_IRQn ;                
   
    i = 0 ;
   
    while(1){}        // Wait for interrupt
}
void TIM2_IRQHandler(void){
    TIM2->SR             &= ~TIM_SR_UIF;                // Clear Timer Flag
    i++ ;
    if(i<=4)GPIOC->ODR    &=     ~(1<<13) ;
        else  GPIOC->ODR    |=     (1<<13) ;  
    if(i>5) i = 0 ;
}

==========
//  T32.c

#include <stm32f10x.h>

int main(void){
    int i,j,k ;
  
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;  
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

//  SPI1
  RCC->APB2ENR    |=         RCC_APB2ENR_IOPAEN ;   
    GPIOA->CRL         &=            ~GPIO_CRL_MODE5 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF5  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE5_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF5_1 ;        // Sck (Alt Ftn)  Pushpull
    GPIOA->CRL         &=            ~GPIO_CRL_MODE6 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF6  ;            // Mask
    // GPIOA->CRL                                                           // Input
    // GPIOA->CRL                                                             // MISO float  
    GPIOA->CRL         &=            ~GPIO_CRL_MODE7 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF7  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE7_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF7_1 ;        // MOSI (Alt Ftn)  Pushpull
  
  RCC->APB2ENR  |=          RCC_APB2ENR_SPI1EN ;
    SPI1->CR1            |=    SPI_CR1_BR ;                    // f/256
    SPI1->CR1            &=    ~SPI_CR1_DFF ;                // 8-bit
    SPI1->CR1            &=    ~SPI_CR1_CPOL ;                // POL=0
    SPI1->CR1            &=    ~SPI_CR1_CPHA ;                // Rising edge
    SPI1->CR1            &=    ~SPI_CR1_LSBFIRST ;        // MSB first
    SPI1->CR1            |=    SPI_CR1_SSM ;                    // SSM=1  
    SPI1->CR1            |=    SPI_CR1_SSI;                    // SSI=1
  SPI1->CR1     |=  SPI_CR1_MSTR ;                 // Master
    SPI1->CR1     |=  SPI_CR1_SPE ;                 // Enable SPI
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = 0x53 ;                                        // Just show something
    k = 0 ;
    while(1){
    //    for(i=0;i<=1000;i++){for(j=0;j<=10000;j++);}  // Software delay
    //    while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
    //    SPI1->DR = k ;                                          
    //    k++ ;
    }      
}

==========
//  T40.c    Check clock source

#include <stm32f10x.h>
int i ;

int main(void){
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

//  SPI1 
  RCC->APB2ENR    |=         RCC_APB2ENR_IOPAEN ;    
    GPIOA->CRL         &=            ~GPIO_CRL_MODE5 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF5  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE5_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF5_1 ;        // Sck (Alt Ftn)  Pushpull
    GPIOA->CRL         &=            ~GPIO_CRL_MODE6 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF6  ;            // Mask
    // GPIOA->CRL                                                           // Input
    // GPIOA->CRL                                                             // MISO float   
    GPIOA->CRL         &=            ~GPIO_CRL_MODE7 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF7  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE7_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF7_1 ;        // MOSI (Alt Ftn)  Pushpull
   
  RCC->APB2ENR  |=          RCC_APB2ENR_SPI1EN ;
    SPI1->CR1            |=    SPI_CR1_BR ;                    // f/256
    SPI1->CR1            &=    ~SPI_CR1_DFF ;                // 8-bit
    SPI1->CR1            &=    ~SPI_CR1_CPOL ;                // POL=0
    SPI1->CR1            &=    ~SPI_CR1_CPHA ;                // Rising edge
    SPI1->CR1            &=    ~SPI_CR1_LSBFIRST ;        // MSB first
    SPI1->CR1            |=    SPI_CR1_SSM ;                    // SSM=1   
    SPI1->CR1            |=    SPI_CR1_SSI;                    // SSI=1
  SPI1->CR1     |=  SPI_CR1_MSTR ;                 // Master
    SPI1->CR1     |=  SPI_CR1_SPE ;                 // Enable SPI
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = 0x53 ;                                        // Just show something

    i = RCC->CFGR ;
    while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = i&0xFF ;                                   
    while(1) ;

//  Timer 2
    RCC->APB1ENR    |=     RCC_APB1ENR_TIM2EN ;
    TIM2->PSC = 7999 ;                        // 8000   1 ms
  TIM2->ARR = 999 ;                            // 1000   1 s
  TIM2->CR1     |= TIM_CR1_CEN ;                 // Enable Timer
  TIM2->SR      &= ~TIM_SR_UIF;           // Clear Timer Flag
  TIM2->DIER    |= TIM_DIER_UIE ;                // Enable Timer Interrupt

    NVIC->ISER[0]    |= 1<<TIM2_IRQn ;                
   
    i = 0 ;
    while(1){}        // Wait for interrupt
}
void TIM2_IRQHandler(void){
    TIM2->SR             &= ~TIM_SR_UIF;                // Clear Timer Flag
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = i ;                                       
    i++ ;
    if(i==200) i = 0 ;                                            // 0 to 199
}

==========

//  T42.c    HSI 8-MHz

#include <stm32f10x.h>
int i ;

int main(void){
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

//  SPI1 
  RCC->APB2ENR    |=         RCC_APB2ENR_IOPAEN ;    
    GPIOA->CRL         &=            ~GPIO_CRL_MODE5 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF5  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE5_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF5_1 ;        // Sck (Alt Ftn)  Pushpull
    GPIOA->CRL         &=            ~GPIO_CRL_MODE6 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF6  ;            // Mask
    // GPIOA->CRL                                                           // Input
    // GPIOA->CRL                                                             // MISO float   
    GPIOA->CRL         &=            ~GPIO_CRL_MODE7 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF7  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE7_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF7_1 ;        // MOSI (Alt Ftn)  Pushpull
   
  RCC->APB2ENR  |=          RCC_APB2ENR_SPI1EN ;
    SPI1->CR1            |=    SPI_CR1_BR ;                    // f/256
    SPI1->CR1            &=    ~SPI_CR1_DFF ;                // 8-bit
    SPI1->CR1            &=    ~SPI_CR1_CPOL ;                // POL=0
    SPI1->CR1            &=    ~SPI_CR1_CPHA ;                // Rising edge
    SPI1->CR1            &=    ~SPI_CR1_LSBFIRST ;        // MSB first
    SPI1->CR1            |=    SPI_CR1_SSM ;                    // SSM=1   
    SPI1->CR1            |=    SPI_CR1_SSI;                    // SSI=1
  SPI1->CR1     |=  SPI_CR1_MSTR ;                 // Master
    SPI1->CR1     |=  SPI_CR1_SPE ;                 // Enable SPI
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = 0x53 ;                                        // Just show something

    RCC->CR             |=      RCC_CR_HSION ;                // Turn on HSI 
    RCC->CFGR            &=     ~RCC_CFGR_SW ;                // Mask                                                                                    
                                                                                    // Use HSI
    while( (RCC->CR&RCC_CR_HSIRDY)==0 );        // Wait till HSI ready
    while( (RCC->CFGR&RCC_CFGR_SWS)!=0 );        // Wait till HSI used                   
   
//  Timer 2
    RCC->APB1ENR    |=     RCC_APB1ENR_TIM2EN ;
    TIM2->PSC = 7999 ;                        // 8000   1 ms
  TIM2->ARR = 999 ;                            // 1000   1 s
  TIM2->CR1     |= TIM_CR1_CEN ;                 // Enable Timer
  TIM2->SR      &= ~TIM_SR_UIF;           // Clear Timer Flag
  TIM2->DIER    |= TIM_DIER_UIE ;                // Enable Timer Interrupt

    NVIC->ISER[0]    |= 1<<TIM2_IRQn ;                
   
    i = 0 ;
    while(1){}        // Wait for interrupt
}
void TIM2_IRQHandler(void){
    TIM2->SR             &= ~TIM_SR_UIF;                // Clear Timer Flag
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = i ;                                       
    i++ ;
    if(i==200) i = 0 ;                                            // 0 to 199
}

==========
//  T43.c    HSI 8-MHz PLL x4

#include <stm32f10x.h>
int i ;

int main(void){
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

//  SPI1 
  RCC->APB2ENR    |=         RCC_APB2ENR_IOPAEN ;    
    GPIOA->CRL         &=            ~GPIO_CRL_MODE5 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF5  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE5_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF5_1 ;        // Sck (Alt Ftn)  Pushpull
    GPIOA->CRL         &=            ~GPIO_CRL_MODE6 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF6  ;            // Mask
    // GPIOA->CRL                                                           // Input
    // GPIOA->CRL                                                             // MISO float   
    GPIOA->CRL         &=            ~GPIO_CRL_MODE7 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF7  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE7_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF7_1 ;        // MOSI (Alt Ftn)  Pushpull
   
  RCC->APB2ENR  |=          RCC_APB2ENR_SPI1EN ;
    SPI1->CR1            |=    SPI_CR1_BR ;                    // f/256
    SPI1->CR1            &=    ~SPI_CR1_DFF ;                // 8-bit
    SPI1->CR1            &=    ~SPI_CR1_CPOL ;                // POL=0
    SPI1->CR1            &=    ~SPI_CR1_CPHA ;                // Rising edge
    SPI1->CR1            &=    ~SPI_CR1_LSBFIRST ;        // MSB first
    SPI1->CR1            |=    SPI_CR1_SSM ;                    // SSM=1   
    SPI1->CR1            |=    SPI_CR1_SSI;                    // SSI=1
  SPI1->CR1     |=  SPI_CR1_MSTR ;                 // Master
    SPI1->CR1     |=  SPI_CR1_SPE ;                 // Enable SPI
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = 0x53 ;                                        // Just show something

    RCC->CR             |=      RCC_CR_HSION ;                // Turn on HSI 
    while( (RCC->CR&RCC_CR_HSIRDY)==0 );        // Wait till HSI ready
    RCC->CFGR            &=     ~RCC_CFGR_SW ;                // Mask                                                                                    
                                                                                    // Use HSI
    while( (RCC->CFGR&RCC_CFGR_SWS)!=0 );        // Wait till HSI used               
    RCC->CR             &=     ~RCC_CR_PLLON ;                // Turn off PLL   
    RCC->CFGR            &=     ~RCC_CFGR_PLLMULL ;        // Mask    
    RCC->CFGR            |=      RCC_CFGR_PLLMULL_1 ;    // x4
    RCC->CFGR            &=     ~RCC_CFGR_PLLSRC ;        // Mask
                                                                                    // Use HSI /2
    RCC->CR             |=      RCC_CR_PLLON ;                // Turn on PLL
    while( (RCC->CR&RCC_CR_PLLRDY)==0 );        // Wait till PLL ready
    RCC->CFGR            &=     ~RCC_CFGR_SW ;                // Mask        
    RCC->CFGR            |=      RCC_CFGR_SW_PLL ;        // Use PLL                           
    while( (RCC->CFGR&RCC_CFGR_SWS_PLL)==0 );        // Wait till PLL used               

   
//  Timer 2
    RCC->APB1ENR    |=     RCC_APB1ENR_TIM2EN ;
    TIM2->PSC = 7999 ;                        // 8000   1 ms
  TIM2->ARR = 999 ;                            // 1000   1 s
  TIM2->CR1     |= TIM_CR1_CEN ;                 // Enable Timer
  TIM2->SR      &= ~TIM_SR_UIF;           // Clear Timer Flag
  TIM2->DIER    |= TIM_DIER_UIE ;                // Enable Timer Interrupt

    NVIC->ISER[0]    |= 1<<TIM2_IRQn ;                
   
    i = 0 ;
    while(1){}        // Wait for interrupt
}
void TIM2_IRQHandler(void){
    TIM2->SR             &= ~TIM_SR_UIF;                // Clear Timer Flag
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = i ;                                       
    i++ ;
    if(i==200) i = 0 ;                                            // 0 to 199
}

==========
//  T44.c    HSI 8-MHz /2 PLL x16    64 MHz  

#include <stm32f10x.h>
int i ;

int main(void){
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

//  SPI1 
  RCC->APB2ENR    |=         RCC_APB2ENR_IOPAEN ;    
    GPIOA->CRL         &=            ~GPIO_CRL_MODE5 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF5  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE5_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF5_1 ;        // Sck (Alt Ftn)  Pushpull
    GPIOA->CRL         &=            ~GPIO_CRL_MODE6 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF6  ;            // Mask
    // GPIOA->CRL                                                           // Input
    // GPIOA->CRL                                                             // MISO float   
    GPIOA->CRL         &=            ~GPIO_CRL_MODE7 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF7  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE7_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF7_1 ;        // MOSI (Alt Ftn)  Pushpull
   
  RCC->APB2ENR  |=          RCC_APB2ENR_SPI1EN ;
    SPI1->CR1            |=    SPI_CR1_BR ;                    // f/256
    SPI1->CR1            &=    ~SPI_CR1_DFF ;                // 8-bit
    SPI1->CR1            &=    ~SPI_CR1_CPOL ;                // POL=0
    SPI1->CR1            &=    ~SPI_CR1_CPHA ;                // Rising edge
    SPI1->CR1            &=    ~SPI_CR1_LSBFIRST ;        // MSB first
    SPI1->CR1            |=    SPI_CR1_SSM ;                    // SSM=1   
    SPI1->CR1            |=    SPI_CR1_SSI;                    // SSI=1
  SPI1->CR1     |=  SPI_CR1_MSTR ;                 // Master
    SPI1->CR1     |=  SPI_CR1_SPE ;                 // Enable SPI
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = 0x53 ;                                        // Just show something

    RCC->CR             |=      RCC_CR_HSION ;                // Turn on HSI 
    while( (RCC->CR&RCC_CR_HSIRDY)==0 );        // Wait till HSI ready
    RCC->CFGR            &=     ~RCC_CFGR_SW ;                // Mask                                                                                    
                                                                                    // Use HSI
    while( (RCC->CFGR&RCC_CFGR_SWS)!=0 );        // Wait till HSI used               
    RCC->CR             &=     ~RCC_CR_PLLON ;                // Turn off PLL   
    RCC->CFGR            &=     ~RCC_CFGR_PLLMULL ;        // Mask    
    RCC->CFGR            |=      RCC_CFGR_PLLMULL ;        // x16
    RCC->CFGR            &=     ~RCC_CFGR_PLLSRC ;        // Mask
                                                                                    // Use HSI /2
    RCC->CR             |=      RCC_CR_PLLON ;                // Turn on PLL
    while( (RCC->CR&RCC_CR_PLLRDY)==0 );        // Wait till PLL ready
    RCC->CFGR            &=     ~RCC_CFGR_SW ;                // Mask        
    RCC->CFGR            |=      RCC_CFGR_SW_PLL ;        // Use PLL                           
    while( (RCC->CFGR&RCC_CFGR_SWS_PLL)==0 );        // Wait till PLL used               

   
//  Timer 2
    RCC->APB1ENR    |=     RCC_APB1ENR_TIM2EN ;
    TIM2->PSC = 7999 ;                        // 64000000 / 8000   8 kHz
  TIM2->ARR = 7999 ;                        // 8000 / 8000    1 s
  TIM2->CR1     |= TIM_CR1_CEN ;                 // Enable Timer
  TIM2->SR      &= ~TIM_SR_UIF;           // Clear Timer Flag
  TIM2->DIER    |= TIM_DIER_UIE ;                // Enable Timer Interrupt

    NVIC->ISER[0]    |= 1<<TIM2_IRQn ;                
   
    i = 0 ;
    while(1){}        // Wait for interrupt
}
void TIM2_IRQHandler(void){
    TIM2->SR             &= ~TIM_SR_UIF;                // Clear Timer Flag
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = i ;                                       
    i++ ;
    if(i==200) i = 0 ;                                            // 0 to 199
}

==========
//  T46.c    Select HSE

#include <stm32f10x.h>
int i ;

int main(void){
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

//  SPI1 
  RCC->APB2ENR    |=         RCC_APB2ENR_IOPAEN ;    
    GPIOA->CRL         &=            ~GPIO_CRL_MODE5 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF5  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE5_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF5_1 ;        // Sck (Alt Ftn)  Pushpull
    GPIOA->CRL         &=            ~GPIO_CRL_MODE6 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF6  ;            // Mask
    // GPIOA->CRL                                                           // Input
    // GPIOA->CRL                                                             // MISO float   
    GPIOA->CRL         &=            ~GPIO_CRL_MODE7 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF7  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE7_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF7_1 ;        // MOSI (Alt Ftn)  Pushpull
   
  RCC->APB2ENR  |=          RCC_APB2ENR_SPI1EN ;
    SPI1->CR1            |=    SPI_CR1_BR ;                    // f/256
    SPI1->CR1            &=    ~SPI_CR1_DFF ;                // 8-bit
    SPI1->CR1            &=    ~SPI_CR1_CPOL ;                // POL=0
    SPI1->CR1            &=    ~SPI_CR1_CPHA ;                // Rising edge
    SPI1->CR1            &=    ~SPI_CR1_LSBFIRST ;        // MSB first
    SPI1->CR1            |=    SPI_CR1_SSM ;                    // SSM=1   
    SPI1->CR1            |=    SPI_CR1_SSI;                    // SSI=1
  SPI1->CR1     |=  SPI_CR1_MSTR ;                 // Master
    SPI1->CR1     |=  SPI_CR1_SPE ;                 // Enable SPI
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = 0x53 ;                                        // Just show something

    RCC->CR             &=     ~RCC_CR_HSEBYP ;            // HSE not bypassed
    RCC->CR             |=      RCC_CR_HSEON ;                // Turn on HSE
    while( (RCC->CR&RCC_CR_HSERDY)==0 );        // Wait till HSE ready
    RCC->CFGR            &=     ~RCC_CFGR_SW ;                // Mask                                                                                    
    RCC->CFGR            |=      RCC_CFGR_SW_HSE ;        // Use HSE
    while( (RCC->CFGR&RCC_CFGR_SWS_HSE)!=RCC_CFGR_SWS_HSE );        // Wait till HSE used                                                                   

//  Timer 2
    RCC->APB1ENR    |=     RCC_APB1ENR_TIM2EN ;
    TIM2->PSC = 7999 ;                        // 8000   1 ms
  TIM2->ARR = 999 ;                            // 1000   1 s
  TIM2->CR1     |= TIM_CR1_CEN ;                 // Enable Timer
  TIM2->SR      &= ~TIM_SR_UIF;           // Clear Timer Flag
  TIM2->DIER    |= TIM_DIER_UIE ;                // Enable Timer Interrupt

    NVIC->ISER[0]    |= 1<<TIM2_IRQn ;                
   
    i = 0 ;
    while(1){}        // Wait for interrupt
}
void TIM2_IRQHandler(void){
    TIM2->SR             &= ~TIM_SR_UIF;                // Clear Timer Flag
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = i ;                                       
    i++ ;
    if(i==200) i = 0 ;                                            // 0 to 199
}

==========
//  T47.c    HSE with PLL x9    72 MHz

#include <stm32f10x.h>
int i ;

int main(void){
   
    RCC->APB2ENR    |=         RCC_APB2ENR_IOPCEN ;   
    GPIOC->CRH         &=            ~GPIO_CRH_MODE13 ;        // Mask
    GPIOC->CRH         &=            ~GPIO_CRH_CNF13 ;            // Mask
  GPIOC->CRH         |=         GPIO_CRH_MODE13_1 ;  // 00 10 PushPull Output 2 MHz
  GPIOC->ODR    &=         ~(1<<13) ;               // Clear bit 13  LED on.

//  SPI1 
  RCC->APB2ENR    |=         RCC_APB2ENR_IOPAEN ;    
    GPIOA->CRL         &=            ~GPIO_CRL_MODE5 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF5  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE5_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF5_1 ;        // Sck (Alt Ftn)  Pushpull
    GPIOA->CRL         &=            ~GPIO_CRL_MODE6 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF6  ;            // Mask
    // GPIOA->CRL                                                           // Input
    // GPIOA->CRL                                                             // MISO float   
    GPIOA->CRL         &=            ~GPIO_CRL_MODE7 ;            // Mask
    GPIOA->CRL         &=            ~GPIO_CRL_CNF7  ;            // Mask
    GPIOA->CRL         |=         GPIO_CRL_MODE7_1 ;      // Output 2 MHz
    GPIOA->CRL         |=              GPIO_CRL_CNF7_1 ;        // MOSI (Alt Ftn)  Pushpull
   
  RCC->APB2ENR  |=          RCC_APB2ENR_SPI1EN ;
    SPI1->CR1            |=    SPI_CR1_BR ;                    // f/256
    SPI1->CR1            &=    ~SPI_CR1_DFF ;                // 8-bit
    SPI1->CR1            &=    ~SPI_CR1_CPOL ;                // POL=0
    SPI1->CR1            &=    ~SPI_CR1_CPHA ;                // Rising edge
    SPI1->CR1            &=    ~SPI_CR1_LSBFIRST ;        // MSB first
    SPI1->CR1            |=    SPI_CR1_SSM ;                    // SSM=1   
    SPI1->CR1            |=    SPI_CR1_SSI;                    // SSI=1
  SPI1->CR1     |=  SPI_CR1_MSTR ;                 // Master
    SPI1->CR1     |=  SPI_CR1_SPE ;                 // Enable SPI
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = 0x53 ;                                        // Just show something

    RCC->CR             &=     ~RCC_CR_HSEBYP ;            // HSE not bypassed
    RCC->CR             |=      RCC_CR_HSEON ;                // Turn on HSE
    while( (RCC->CR&RCC_CR_HSERDY)==0 );        // Wait till HSE ready
    RCC->CFGR            &=     ~RCC_CFGR_SW ;                // Mask                                                                                    
    RCC->CFGR            |=      RCC_CFGR_SW_HSE ;        // Use HSE
    while( (RCC->CFGR&RCC_CFGR_SWS_HSE)!=RCC_CFGR_SWS_HSE );        // Wait till HSE used                                                                   

    RCC->CR             &=     ~RCC_CR_PLLON ;                // Turn off PLL   
    RCC->CFGR            &=     ~RCC_CFGR_PLLMULL ;        // Mask    
    RCC->CFGR            |=      RCC_CFGR_PLLMULL_2 ;   
    RCC->CFGR            |=      RCC_CFGR_PLLMULL_1 ;   
    RCC->CFGR            |=      RCC_CFGR_PLLMULL_0 ;    // x9
    RCC->CFGR            &=     ~RCC_CFGR_PLLXTPRE ;    // HSE not /2
    RCC->CFGR            |=      RCC_CFGR_PLLSRC ;        // Use HSE
    RCC->CR             |=      RCC_CR_PLLON ;                // Turn on PLL
    while( (RCC->CR&RCC_CR_PLLRDY)==0 );        // Wait till PLL ready
    RCC->CFGR            &=     ~RCC_CFGR_SW ;                // Mask        
    RCC->CFGR            |=      RCC_CFGR_SW_PLL ;        // Use PLL                           
    while( (RCC->CFGR&RCC_CFGR_SWS_PLL)==0 );        // Wait till PLL used               

//  Timer 2
    RCC->APB1ENR    |=     RCC_APB1ENR_TIM2EN ;
    TIM2->PSC = 8999 ;                        // 72 MHz / 9k = 8k
  TIM2->ARR = 7999 ;                        // 8k/8000   1 s
  TIM2->CR1     |= TIM_CR1_CEN ;                 // Enable Timer
  TIM2->SR      &= ~TIM_SR_UIF;           // Clear Timer Flag
  TIM2->DIER    |= TIM_DIER_UIE ;                // Enable Timer Interrupt

    NVIC->ISER[0]    |= 1<<TIM2_IRQn ;                
   
    i = 0 ;
    while(1){}        // Wait for interrupt
}
void TIM2_IRQHandler(void){
    TIM2->SR             &= ~TIM_SR_UIF;                // Clear Timer Flag
  while((SPI1->SR&SPI_SR_TXE)==0);                 // Wait till transmitter empty
  SPI1->DR = i ;                                       
    i++ ;
    if(i==200) i = 0 ;                                            // 0 to 199
}

==========

==========



 

Friday, 14 July 2017

ATMEGA16A

20220503.2

ATMEGA16A

====================
Equipment and Tools:
1  PC
2  Internet access
3  An IDE  (IAR Embedded Workbench)
4  USBASP
5  ATMEGA16A
 PCB with socket 
7  A breadboard, connectors, pins etc.

====================
Notes:
1  Knowledge in C language is assumed.
2  Installing the driver for the USBASP may be troublesome.
3  The USBASP may be used with the AVRDUDESS software.
====================
Set up:
Download and install the IDE.
Download and read the USBASP-UG (User Guide), from ProtoStack.
Plug the USBASP to the PC.
Install the driver as described in the guide.
Download, install and test AVRDUDESS.   
 
Insert the ATMEGA16A onto the board.
Connect the board to the USBASP.
Check the circuit using  AVRDUDESS to detect the chip.
         


====================
Programming:
Launch the IAR Embedded Workbench.
Create a New (Empty) Project in the folder. (P16)
In the ‘Options’, select ATmega16 as the processor and ‘Other’ for the Linker Output.
Type in a program, name it as main.c and add it to the project.
Always save the program file.
Make, and check that an output file P16.a19 has been produced.
Flash the file into the ATMEGA16 through the AVRDUDESS. 
See(Verify) that the ATMEGA16 runs according to the program.
====================
Starting examples:
AT00a     To test program compilation and downloading.
AT00b     To keep the microcontroller within user control.
AT01LEDa    To turn on the LED connected to PortA bit 0.
AT01LEDb    To turn off the LED connected to PortA bit 0.
AT01LEDt    To toggle the LED connected to PortA bit 0.    

//  AT00a

int main( void )
{
  return 0;
}

//  AT00b

int main( void )
{
  while(1);
}

//  AT01LEDa    Set Port A bit 0

#include <iom16.h>

int main( void )
{
  PORTA |= 0x01 ;       // set Bit 0 
  DDRA  |= 0x01 ;       // Bit 0 Output
  
  while(1);
}

//  AT01LEDb    Clear Port A bit 0

#include <iom16.h>

int main( void )
{
  PORTA &= ~0x01 ;      // clear Bit 0 
  DDRA  |= 0x01 ;       // Bit 0 Output
  
  while(1);
}

//  AT01LEDt    Toggle Port A bit 0 

#include <iom16.h>

int main( void )
{
  int i;
  
  PORTA &= ~0x01 ;      // clear Bit 0 
  DDRA  |= 0x01 ;       // Bit 0 Output
  
  while(1){
    for(i=0;i<=30000;i++){;}    // Do not exceed 32767
    PORTA |= 0x01 ;             // set Bit 0 
    for(i=0;i<=30000;i++){;}  
    PORTA &= ~0x01 ;            // clear Bit 0 
  }
}

20220503.2


T21     Timer 2. 
T22     Timer 2 Interrupt.

====================
Fuses:

Reference:   AVR Tutorial:   http://www.ladyada.net/learn/avr/avrdude.html
                    AVR Fuse Calculator:   http://www.engbedded.com/fusecalc/

Change the clock to 8 MHz by  AVRDUDE –c usbasp –p m16 –U lfuse:w:0xe4:m
After the clock change, T15 would blink very fast, T21 does not seem to work.


====================
Further notes on the programming examples:


T16     To blink the LED at 8 MHz.
T23     Timer 2 Interrupt at 8 MHz.

T30     LCD 1602     8-pin operation

               ATMEGA16           LCD 1602
               all 8 Port D bits      all 8 Data bits
               Port A bit 1             RS
               Port A bit 0             E
                                               W/R connect to Ground
                                               Vo connect to Ground through a 1-k resistor 
T31     LCD 1602.
               ATMEGA16           LCD 1602
               Port D bits 7,6,5,4  Data bits 7,6,5,4
               Port A bit 1             RS
               Port A bit 0             E
                                               W/R connect to Ground
                                               Vo connect to Ground through a 1-k resistor



====================
Programming examples:
==========
// T10.c

int main(){
 
  return 0;
}

==========
// T11.c

int main(){
 
  while(1);
}
==========
// T12.c
#include <iom16.h>

int main(){
 
  PORTA = 0x01 ;        // Bit 0 set (Off)
  DDRA  = 0x01 ;        // Bit 0 Output
 
  while(1);
}
==========
// T13.c
#include <iom16.h>

int main(){
 
  PORTA = 0x00 ;        // Bit 0 clear (ON)
  DDRA  = 0x01 ;        // Bit 0 Output
 
  while(1);
}
==========
// T14.c
#include <iom16.h>

int main(){
 
  PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
  DDRA  |= 1<<0 ;       // Bit 0 Output

  while(1);
}
==========
// T15.c
#include <iom16.h>

int main(){
  int i ;
 
  PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
  DDRA  |= 1<<0 ;       // Bit 0 Output

  while(1){
    PORTA |= 1<<0 ;             // Bit 0 set (Off)
    for(i=0;i<=30000;i++){ ; }  // Software delay
    PORTA &= ~(1<<0) ;          // Bit 0 clear (ON)
    for(i=0;i<=30000;i++){ ; }  // Software delay
  }

  // while(1);
}
==========

// T16.c      8 MHz
#include <iom16.h>

int main(){
  int i,j ;
 
  PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
  DDRA  |= 1<<0 ;       // Bit 0 Output

  while(1){
    PORTA |= 1<<0 ;             // Bit 0 set (Off)
    for(i=0;i<=200;i++){for(j=0;j<=1000;j++);}  // Software delay
    PORTA &= ~(1<<0) ;          // Bit 0 clear (ON)
    for(i=0;i<=200;i++){for(j=0;j<=1000;j++);}  // Software delay
  }

  // while(1);
}
==========
// T21.c
#include <iom16.h>

int main(){
 
  PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
  DDRA  |= 1<<0 ;       // Bit 0 Output

  TCCR0 = 0x05 ;        // T0 ON, clk/1024

  while(1){
    if( TCNT0>=0x20 )   PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
                else    PORTA |= 1<<0 ;       // Bit 0 set (Off)
  }

  // while(1);
}
==========
// T22.c
#include <iom16.h>
#include <intrinsics.h>

int i;

int main(){
 
  PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
  DDRA  |= 1<<0 ;       // Bit 0 Output

  __disable_interrupt();
  TCCR0 = 0x05 ;        // T0 ON, clk/1024
  TIMSK |= 0x01 ;       // 0x01 is TOIE0
  __enable_interrupt();

  i = 0 ;

  while(1);     // Wait for interrupts
}

// Interrupt handler for TCNT0 Overflow
#pragma vector=TIMER0_OVF_vect
__interrupt void TOV0_Handler(void)
{
  i++ ;
  if(i<=5) PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
     else  PORTA |= 1<<0 ;       // Bit 0 set (Off)
  if(i==7) i = 0 ;
}
==========    
// T23.c      8 MHz
#include <iom16.h>
#include <intrinsics.h>

int i;

int main(){
 
  PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
  DDRA  |= 1<<0 ;       // Bit 0 Output

  __disable_interrupt();
  TCCR0 = 0x05 ;        // T0 ON, clk/1024
  TIMSK |= 0x01 ;       // 0x01 is TOIE0
  __enable_interrupt();

  i = 0 ;

  while(1);     // Wait for interrupts
}

// Interrupt handler for TCNT0 Overflow
#pragma vector=TIMER0_OVF_vect
__interrupt void TOV0_Handler(void)
{
  i++ ;
  if(i<=50) PORTA &= ~(1<<0) ;    // Bit 0 clear (ON)
      else  PORTA |= 1<<0 ;       // Bit 0 set (Off)
  if(i==70) i = 0 ;
}
==========

// T30.c      LCD 1602    8-pin(8-bit) mode
#include <iom16.h>
#include <intrinsics.h>
void LCD_E(int K);

int main(){
  int i ;
 
  PORTA &= ~(1<<0) ;    // Bit 0 clear    E = 0
  DDRA  |= 1<<0 ;       // Bit 0 Output
  PORTA &= ~(1<<1) ;    // Bit 1 clear    RS = 0
  DDRA  |= 1<<1 ;       // Bit 1 Output
  PORTD = 0x00 ;
  DDRD |= 0xFF ;        // 7,6,5,4,3,2,1,0  Output

  PORTA &= ~(1<<1) ;    // Bit 1 clear    RS = 0

  LCD_E(0x30);    // 3 times 0x30
  LCD_E(0x30);    // to ensure LCD is
  LCD_E(0x30);    // into 8-pin mode
  LCD_E(0x38);
 
  LCD_E(0x0F);
  LCD_E(0x06);
  LCD_E(0x01);
  for(i=0;i<=30000;i++);      // Give time for clear screen

  LCD_E(0x80);
 
  PORTA |=  (1<<1) ;    // Bit 1 set    RS = 1
  LCD_E('H');
  LCD_E('a');
  LCD_E('p');
  LCD_E('p');
  LCD_E('y');
  LCD_E(' ');
  LCD_E('B');
  LCD_E('i');
  LCD_E('r');
  LCD_E('t');
  LCD_E('h');
  LCD_E('d');
  LCD_E('a');
  LCD_E('y'); 
 
  PORTA &= ~(1<<1) ;    // Bit 1 clear    RS = 0
  LCD_E(0xC0);

  PORTA |=  (1<<1) ;    // Bit 1 set    RS = 1
  LCD_E('Y');
  LCD_E('o');
  LCD_E('n');
  LCD_E('g');
  LCD_E(' ');
  LCD_E('Y');
  LCD_E('o');
  LCD_E('k');
  LCD_E('e');
  LCD_E(' ');
  LCD_E('K');
  LCD_E('e');
  LCD_E('o');
  LCD_E('w');
  LCD_E(' ');
 
  PORTA &= ~(1<<1) ;    // Bit 1 clear    RS = 0
  LCD_E(0xD3);          // Move out cursor

  while(1);     // Wait for interrupts
}
void LCD_E(int K){
  int i ;
    PORTD = K ;
    for(i=0;i<=1000;i++){ ; }    
    PORTA |=  (1<<0) ;    // Bit 0 set      E = 1
    for(i=0;i<=1000;i++){ ; }
    PORTA &= ~(1<<0) ;    // Bit 0 clear    E = 0
    for(i=0;i<=1000;i++){ ; }
}

==========
// T31.c
#include <iom16.h>
#include <intrinsics.h>
void LCD_E(int K);

int main(){
  unsigned int i ;
 
  PORTA &= ~(1<<0) ;    // Bit 0 clear    E = 0
  DDRA  |= 1<<0 ;       // Bit 0 Output
  PORTA &= ~(1<<1) ;    // Bit 1 clear    RS = 0
  DDRA  |= 1<<1 ;       // Bit 1 Output
  PORTD = 0x00 ;
  DDRD |= 0xF0 ;        // 7,6,5,4  Output

  PORTD = 0x30 ;
  LCD_E(1000);
  PORTD = 0x30 ;
  LCD_E(1000);
  PORTD = 0x30 ;
  LCD_E(1000);
  PORTD = 0x30 ;
  LCD_E(1000);
  PORTD = 0x30 ;
  LCD_E(1000);
  PORTD = 0x20 ;
  LCD_E(1000);
  PORTD = 0x20 ;
  LCD_E(1000);
  PORTD = 0x80 ;
  LCD_E(1000);
 
  PORTD = 0x00 ;
  LCD_E(1000);
  PORTD = 0xF0 ;
  LCD_E(1000);
  PORTD = 0x00 ;
  LCD_E(1000);
  PORTD = 0x60 ;
  LCD_E(1000);
  PORTD = 0x00 ;
  LCD_E(1000);
  PORTD = 0x10 ;
  LCD_E(1000);
  for(i=0;i<=50000;i++);      // Give time for clear screen

  PORTD = 0x80 ;
  LCD_E(1000);
  PORTD = 0x90 ;
  LCD_E(1000);
 
  PORTA |=  (1<<1) ;    // Bit 1 set    RS = 1
  PORTD = 0x51 ;
  LCD_E(1000);
  PORTD = 0x31 ;
  LCD_E(1000);
 
  while(1);     // Wait for interrupts
}
void LCD_E(int K){
  int i ;
    for(i=0;i<=K;i++){ ; }     
    PORTA |=  (1<<0) ;    // Bit 0 set      E = 1
    for(i=0;i<=K;i++){ ; }
    PORTA &= ~(1<<0) ;    // Bit 0 clear    E = 0
    for(i=0;i<=K;i++){ ; }
}

==========    
Continued at ATmega16KCS: ATmega16KCS (esp32kcs.blogspot.com)