Initialisation Nucleo-F446 by Jens Altenburg

Dependencies:   mbed

main.cpp

Committer:
prof_al
Date:
2021-03-17
Revision:
0:9b6fbe273511

File content as of revision 0:9b6fbe273511:

/********************************************************************
 *
 *  Name:           main.cpp
 *  Beschreibung:   HAL für "Embedded Systems Engineering"
 *  Autor:
 *  Erstellung:     29.05.2020
 *
 *  Revisionsliste
 *  Datum       | Autor         | Änderung
 *  ------------+---------------+--------------------------
 *  29.05.2020  | Altenburg     | Ersterstellung
 *  ------------+---------------+--------------------------
 *  04.02.2021  | Altenburg     | syntaktische Korrekturen
 *  ------------+---------------+--------------------------
 *
 ********************************************************************/
#include "mbed.h"
#include "main.h"
#include "oled.h"

DigitalOut   pinLed4(PC_0);     /* SCL - I2C; rote LED2 */
DigitalInOut pinLed2(PC_2);     /* SDA - I2C; grüne LED */

DigitalOut   pinLed3(PC_7);     /* rote LED1 */

/* Interruptprioritäten */
#define nSystickLevel   31      /* niedrigste Priorität */
#define nMillisecLevel  30      /* aufsteigende Priorität */
#define nSbusTimerLevel 29
#define nSbusUartLevel  28

/* Interrupts global freigeben/sperren */
#define mcIntEnable() \
    { __asm("  cpsie i\n"); }
#define mcIntDisable() \
    { __asm("  cpsid i\n"); }

void vWaitFast( void );          /* 200 ms Warten */
void vWaitSlow( void );          /* 1 Sekunde warten */

volatile word wTimer;/*
* Description :
*/
Def_fFunc afFuncList[] = { vWaitFast, vWaitSlow };/*
* Description : Liste mit Funktionen
*/
Def_fFunc *pafFuncList;/* 
* Description : Zeiger auf Funktionspointerliste 
*/

/****************************************************************************
 *                  Init Systemclock                                        * 
PLLCFGR 0b00100010010000100010110100000100
Reserved: 0
PLLR:      010 = 2
PLLQ:         0010 = 2
Reserved:     0
PLLSRC:        1 = HSE
Reserved:       00 00
PLLP:            10 = 6 
PLLN:              0010110100 = 180
PLLM:                    000100 = 4

CFGR 0b00000000000000001011010000001111
PPRE:              101 = AHB2 clock divided by 4
PPRE:             101 = AHB1 clock divided by 4
Reserved:            00 = 
HPRE:                  0000 = AHB prescaler divided by 1
SWS:                   11 = PLL_R used as the system clock
SW:                  11 = PLL_R selected as system clock

 *      Author  :   J. Altenburg (based on C. Hilgert)                      *
 *      Revison :   17.07.17                                                *
 *      Parameters                                                          *
 *      Input   :   Nothing                                                 *
 *      Output  :   Nothing                                                 *
 ****************************************************************************/
void vSysClockInit(void) {
    volatile dword dw;
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;      /* __PWR_CLK_ENABLE(); */
    PWR->CR |= 0x0000C000;                  /* VOS[1:0] Scale 1 = 0b11 */
    dw = RCC->PLLCFGR;
    dw = 0x22422d04;                        /* PLLCFG-Register einstellen */
    RCC->PLLCFGR = dw;
    PWR->CR |= PWR_CR_ODEN;                 /* overdrive enable */
    while ((PWR->CSR & PWR_CSR_ODRDY) == 0);/* wait until overdrive is ready */
    PWR->CR |= PWR_CR_ODSWEN;
    RCC->CR |= RCC_CR_HSEON;                /* 1. Clocking the controller from external HSC crystal (8 MHz) */
    while ((RCC->CR & RCC_CR_HSERDY) == 0); /* wait until the HSE is ready */
    RCC->CR |= RCC_CR_PLLON;                /* 2. PLL on */
    while ((RCC->CR & RCC_CR_PLLRDY) == 0); /* wait until PLL is locked */
    FLASH->ACR = FLASH_ACR_LATENCY_5WS;     /* Zugriffsverz?gerung */
    dw = RCC->CFGR;
    dw |= (RCC_CFGR_PPRE2_DIV4 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_HPRE_DIV1 | RCC_CFGR_SW_PLLR);
    RCC->CFGR = dw;                         /* APB2 = 45 MHz, APB1 = 45 MHz */
    }

/****************************************************************************
 *                  Init-Port - A                                           * 
 *      Author  :   J. Altenburg (based on C. Hilgert)                      *
 *      Revison :   17.07.17                                                *
 *      Parameters                                                          *
 *      Input   :   Nothing                                                 *
 *      Output  :   Nothing                                                 *
 *      Hinweis :   Beschreibung GPIO_AFR[x] Table 11 im Datasheet          *
 ****************************************************************************/
void vPortAInit(void) {
    dword dw;
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;    /* GPIO-Port A initialisieren */
    dw = GPIOA->MODER;
    dw &= ~(GPIO_MODER_MODE15_Msk   /* PA15 maskieren */
            | GPIO_MODER_MODE0_Msk  /* PA0 - UART4 TX */
            | GPIO_MODER_MODE1_Msk  /* PA1 - UART4 RX */
            | GPIO_MODER_MODE2_Msk  /* PA2 - UART2 TX */
            | GPIO_MODER_MODE3_Msk  /* PA3 - UART2 RX */
            | GPIO_MODER_MODE4_Msk  /* PA4 - SPI1_CS  */
            | GPIO_MODER_MODE5_Msk  /* PA5 - SPI1 SCK */
            | GPIO_MODER_MODE6_Msk  /* PA6 - SPI1 MISO */
            | GPIO_MODER_MODE7_Msk  /* PA7 - SPI1 MOSI */
            | GPIO_MODER_MODE9_Msk  /* PA9 - UART1 TX */
            | GPIO_MODER_MODE10_Msk /* PA10- UART1 RX */
        );
    dw |= (GPIO_MODER_MODE15_0   /* PA15- output */
           | GPIO_MODER_MODE0_1  /* PA0 - alternate output */
           | GPIO_MODER_MODE1_1  /* PA1 - alternate output */
           | GPIO_MODER_MODE2_1  /* PA2 - alternate output */
           | GPIO_MODER_MODE3_1  /* PA3 - alternate output */
           | GPIO_MODER_MODE4_0  /* PA4 - output */
           | GPIO_MODER_MODE5_1  /* PA5 - alternate output */
           | GPIO_MODER_MODE6_1  /* PA6 - alternate output */
           | GPIO_MODER_MODE7_1  /* PA7 - alternate output */
           | GPIO_MODER_MODE9_1  /* PA9 - alternate output */
           | GPIO_MODER_MODE10_1 /* PA10- alternate output */
        );
    GPIOA->MODER = dw;
    dw = GPIOA->OTYPER;
    dw |= GPIO_OTYPER_OT15; /* open drain */
    //GPIOA->OTYPER = dw;
    dw = GPIOA->OSPEEDR;
    dw |= GPIO_OSPEEDR_OSPEED15_1;

    GPIOA->AFR[0] = 0x55507788;
    GPIOA->AFR[1] = 0x00000770;
    //vCS1High(); /* CS BME280 inaktiv */
}

/***************************************************************************
*                  Init Systemticker                                   
*      Author  :   J. Altenburg               
*      Revison :   17.07.17                                      
*      Parameters – alle 15 Millisekunden einen Interrupt       
***************************************************************************/
void vSystickInit( void ) {
    NVIC_SetPriority(SysTick_IRQn, nSystickLevel); /* INT freigeben */
    /* 15m/180MHz^-1 set reload register = 15 Millisekunden */
    SysTick->LOAD = (2700000 - 1); 
    SysTick->VAL = 0;               /* Init Counter */
    SysTick->CTRL = ( SysTick_CTRL_ENABLE_Msk
                     |SysTick_CTRL_CLKSOURCE_Msk
                     |SysTick_CTRL_TICKINT_Msk
                     );
    }


/****************************************************************************
 *                  Timer2                                                  * 
 *      Author  :   J. Altenburg                                            *
 *      Revison :   18.07.17                                                *
 *      Parameters                                                          *
 *      Input   :   Nothing                                                 *
 *      Output  :   Nothing                                                 *
 ****************************************************************************/
void vTimer2Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; /* Power on */
    TIM2->PSC = 8;                      /* 90MHz^-1 * (8+1) = 100 ns */
    TIM2->ARR = 60000;                  /* 100ns * 10000 = 1 ms */
    TIM2->CR1 &= ~TIM_CR1_DIR;          /* aufw?rts z?hlen */
    //TIM2->CCR1  = 20000;
    NVIC_SetPriority(TIM2_IRQn, nMillisecLevel);
    NVIC_EnableIRQ(TIM2_IRQn);
    TIM2->DIER = TIM_DIER_CC1IE; /* compare interrupt enable */
    TIM2->CR1 |= TIM_CR1_CEN;
    }

/****************************************************************************
 *                  Timer4 als Interruptquelle Uhrzeiger-Arithmetik         * 
 *      Author  :   J. Altenburg                                            *
 *      Revison :   21.05.20                                                *
 *      Parameters                                                          *
 *      Input   :   Nothing                                                 *
 *      Output  :   Nothing                                                 *
 ****************************************************************************/
void vTimer4Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; /* Power on */
    TIM4->PSC = 8;                      /* 90MHz^-1 * (8+1) = 100 ns */
    TIM4->ARR = 0xffff;                  /* 100ns * 10000 = 1 ms */
    TIM4->CR1 &= ~TIM_CR1_DIR;          /* aufwärts zählen */
    TIM4->CCR1  = 15000;
    NVIC_SetPriority(TIM4_IRQn, nMillisecLevel);
    NVIC_EnableIRQ(TIM4_IRQn);
    TIM4->DIER = TIM_DIER_CC1IE;        /* compare interrupt enable */
    TIM4->CR1 |= TIM_CR1_CEN;
}

/****************************************************************************
 *                  UART 2                              
 *      Author  :   J. Altenburg 
 *      Revison :   20.07.17                                               
 ****************************************************************************/
void vUart2Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_USART2EN; /* UART2 freigeben */
    USART2->CR3 = 0;                      /* Reset-Value */
    /* 1 Stop Bit; Keine Parität; 8-Databits */
    USART2->CR1 |= (USART_CR1_UE + USART_CR1_RXNEIE + USART_CR1_RE + USART_CR1_TCIE + USART_CR1_TE);
    /* Baudrate UART */
    /* Bit 0-3 sind Fraction->Kommazahl; 15-4 sind Mantissa->ganze Zahl */
    /* UARTDIV = f/(Baud*16); UART5->BRR = UARTDIV << 4 | UARTDIV_Komma */
    /* 146.48 = 45MHz/(19200 * 16) */
    USART2->BRR = (word)((146 << 4) | 5);
#if 0
    NVIC_SetPriority(USART2_IRQn, nMillisecLevel); /* Prioritaet */
    NVIC_EnableIRQ(USART2_IRQn);
#endif
}



/****************************************************************************
 *                  ISR - Systemtimer                                       *
 *                  - Aufruf der APPs alle x ms                             * 
 *                  - Aufruf des "Millisekunden"-Containers                 *           
 *      Author  :   J. Altenburg                                            *
 *      Revison :   17.07.17                                                *
 ****************************************************************************/
extern "C" void SysTick_Handler( void ){
    SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG_Msk;
    //GPIOA->ODR ^= (1<<15); /* Testsignal auf GPIO legen */
    }


/****************************************************************************
 *                  ISR - Timer 2                                           *
 *      Author  :   J. Altenburg                                            *
 *      Revison :   30.08.17                                                *
 *      Parameters                                                          *
 *      Laufzeit:   x.y µs                                       *
 ****************************************************************************/
extern "C" void TIM2_IRQHandler(void) {
    //volatile word w;
    TIM2->SR &= ~TIM_SR_CC1IF; /* clear pending bit (sicherheitshalber) */
    //TIM2->CCR1 += 10000;
    //GPIOA->ODR ^= (1<<15);
    //pinLed2 = !pinLed2;
    }

/****************************************************************************
 *                  ISR - Timer 4                                           *
 *      Author  :   J. Altenburg                                            *
 *      Revison :   30.08.17                                                *
 *      Parameters                                                          *
 *      Laufzeit:   x.y µs                                       *
 ****************************************************************************/
extern "C" void TIM4_IRQHandler(void) {
    //volatile word w;
    TIM4->SR &= ~TIM_SR_CC1IF; /* clear pending bit (sicherheitshalber) */
    TIM4->CCR1  += wTimer;
    wTimer += 1500;
    //GPIOA->ODR ^= (1<<15); /* Testsignal auf GPIO legen */
    }

/* I2C - Zugriff */
void vSDAOutput( void ){        /* SDA-Datenrichtung -> Output */
    pinLed2.output();           /* auf Ausgang setzen */
    }
    
void vSDAInput( void ){         /* SDA-Datenrichtung -> Input */
    pinLed2.input();            /* auf Ausgang setzen */
    }

void vSDA_H( void ){            /* SDA setzen */
    pinLed2 = On;
    }
    
void vSDA_L( void ){            /* SDA löschen */
    pinLed2 = Off;
    }
    
void vSCL_H( void ){            /* SCL setzen */
    pinLed4 = On;
    }
    
void vSCL_L( void ){            /* SCL löschen */
    pinLed4 = Off;
    }


void vI2CDelay( void ){         /* ca. 5µs Verzögerung */
    volatile word wDelay = 6;
    while(wDelay--);
    }

void vI2CShort( void ){         /* ca. 5µs Verzögerung */
    volatile word wDelay = 2;
    while(wDelay--);
    }
/* schnelles Blinken */
void vWaitFast( void ){
    wait(0.2);
    }

/* langsames Blinken */
void vWaitSlow( void ){         
    wait(1);
    }

Def_stValue stRaw1 = {1,1,1,1,1,1,1,1};
Def_stValue stRaw2 = {2,2,2,2,2,2,2,2};

byte bAverage1(Def_stValue stLocal){
    byte i, j = 0;
    for(i = 0; i < 8; i++){
        j = j + stLocal.abData[i];
        }
    return j>>3;
    }

void vAverage2(byte *pAverage, Def_stValue *stLocal){
    byte i, j = 0;
    for(i = 0; i < 8; i++){
        j = j + stLocal->abData[i];
        }
    *pAverage = (j>>3);
    }


int main() {
    byte abText[] = "Hallo OLED!";
    dword dwTime = 11;
    byte bPos = 0;
    byte i = 'A';
    byte y = 0;
    pinLed2.mode(OpenDrain);    /* bidirektionaler Pin */ 
    //pinLed2.output();           /* auf Ausgang setzen */
    mcIntDisable();
    vSysClockInit();
    vPortAInit();
    vSystickInit();
    vTimer2Init();
    vTimer4Init();
    vUart2Init();
    mcIntEnable();
    vOledInit();
    ssd1306_fill4(255, 255, 255, 255);
    ssd1306_fill4(0, 0, 0, 0);
    pafFuncList = &afFuncList[0];              /* referenzieren auf Liste */
    y = bAverage1(stRaw1);
    ssd1306tx_large(y+'0', 4, 10);
    vAverage2(&y, &stRaw2);
    ssd1306tx_large(y+'0', 4, 2);
    y = 1;
    while(1) {
#if 1
        bPos = 0;
        for(i = 0; i < sizeof(abText)-1; i++){
            pinLed3 = 0;
            ssd1306tx_large(abText[i], bPos, 6);
            bPos = bPos + 9;
            pinLed3 = 1;
            USART2->DR = 'J';
            (*(pafFuncList + y))();             /* unterschiedliche Wartezeiten */
            dwTime--;
            if(dwTime == 0){
                dwTime = 11;
                (y == 0) ? y = 1 : y = 0;
                ssd1306_fill4(0, 0, 0, 0);
                }
            GPIOA->ODR ^= (1<<15);
            }
#else
        dwTime = 10000000;
        while(dwTime--);
        pinLed3 = 0;
        ssd1306_setpos(0,0);
        //ssd1306_setpos(bPos, y);
        //ssd1306tx_char(i);
        ssd1306tx_large(i, bPos, y);
        pinLed3 = 1;
        if(i < 'Z') i++;
        else        i = 'A'; 
        bPos = bPos + 9;
        y = y + 2;
#endif
        }
    }