From a84307a4b3de58cbb3dd57dede4588e7bd65b961 Mon Sep 17 00:00:00 2001 From: Yohan Boujon Date: Wed, 22 Mar 2023 15:20:38 +0100 Subject: [PATCH] Init of project with the various libraries. --- .gitignore | 1 + README.md | 0 driver-algu/inc/gpio.h | 27 ++++ driver-algu/inc/timer.h | 19 +++ driver-algu/src/gpio.c | 79 ++++++++++++ driver-algu/src/timer.c | 192 +++++++++++++++++++++++++++ driver-siyo/gpiodriver.c | 70 ++++++++++ driver-siyo/gpiodriver.h | 28 ++++ driver-siyo/timerdriver.c | 162 +++++++++++++++++++++++ driver-siyo/timerdriver.h | 39 ++++++ driver/Lib_Com_Periph_2022.lib | Bin 0 -> 15036 bytes driver/MyI2C.h | 229 +++++++++++++++++++++++++++++++++ driver/MySPI.h | 129 +++++++++++++++++++ 13 files changed, 975 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 driver-algu/inc/gpio.h create mode 100644 driver-algu/inc/timer.h create mode 100644 driver-algu/src/gpio.c create mode 100644 driver-algu/src/timer.c create mode 100644 driver-siyo/gpiodriver.c create mode 100644 driver-siyo/gpiodriver.h create mode 100644 driver-siyo/timerdriver.c create mode 100644 driver-siyo/timerdriver.h create mode 100644 driver/Lib_Com_Periph_2022.lib create mode 100644 driver/MyI2C.h create mode 100644 driver/MySPI.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd33554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.obsidian diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/driver-algu/inc/gpio.h b/driver-algu/inc/gpio.h new file mode 100644 index 0000000..642010c --- /dev/null +++ b/driver-algu/inc/gpio.h @@ -0,0 +1,27 @@ +#ifndef MYGPIO_H +#define MYGPIO_H +#include "stm32f10x.h" + +typedef struct { + GPIO_TypeDef * GPIO; + char GPIO_Pin; //numero de 0 a 15 + char GPIO_Conf; //voir ci dessous +} MyGPIO_Struct_TypeDef; + +#define In_Floating 0x4 +#define In_PullDown 0x7 //faire +#define In_PullUp 0x8 //faire +#define In_Analog 0x0 +#define Out_Ppull 0x2 +#define Out_OD 0x6 +#define AltOut_Ppull 0xA +#define AltOut_OD 0xE + +void MyGPIO_InitClock(void); +void MyGPIO_Init(MyGPIO_Struct_TypeDef * GPIOStructPtr); +int MyGPIO_Read(GPIO_TypeDef * GPIO, char GPIO_Pin); +void MyGPIO_Set(GPIO_TypeDef * GPIO, char GPIO_Pin); +void MyGPIO_Reset(GPIO_TypeDef * GPIO, char GPIO_Pin); +void MyGPIO_Toggle(GPIO_TypeDef * GPIO, char GPIO_Pin); + +#endif diff --git a/driver-algu/inc/timer.h b/driver-algu/inc/timer.h new file mode 100644 index 0000000..281867e --- /dev/null +++ b/driver-algu/inc/timer.h @@ -0,0 +1,19 @@ +#ifndef MYTIMER_H +#define MYTIMER_H +#include "stm32f10x.h" + +typedef struct { + TIM_TypeDef * Timer; + unsigned short ARR; + unsigned short PSC; +} MyTimer_Struct_Typedef; + +void MyTimer_Base_Init(MyTimer_Struct_Typedef * Timer); +void MyTimer_ActiveIT(TIM_TypeDef * Timer, char Prio, void (*IT_function) (void)); +void MyTimer_PWM(TIM_TypeDef * Timer ,char Channel); +void MyTimer_DutyCycle(TIM_TypeDef * Timer, char Channel, unsigned char DutyCycle); + +#define MyTimer_Base_Start(Tim) (Tim.Timer->CR1 |= TIM_CR1_CEN) +#define MyTimer_Base_Stop(Tim) (Tim.Timer->CR1 &= ~TIM_CR1_CEN) + +#endif diff --git a/driver-algu/src/gpio.c b/driver-algu/src/gpio.c new file mode 100644 index 0000000..c4c047f --- /dev/null +++ b/driver-algu/src/gpio.c @@ -0,0 +1,79 @@ +#include "gpio.h" + +void MyGPIO_InitClock(void) { + RCC->APB2ENR |= (0x01 << 2) | (0x01 << 3) | (0x01 << 4); +} + +void MyGPIO_Init(MyGPIO_Struct_TypeDef * GPIOStructPtr) { + if (GPIOStructPtr->GPIO_Pin >= 8) { + switch (GPIOStructPtr->GPIO_Conf) { + case In_PullDown: + GPIOStructPtr->GPIO->CRH &= ~(0xF << (4 * (GPIOStructPtr->GPIO_Pin % 8))); + GPIOStructPtr->GPIO->CRH |= (0x8 << (4 * (GPIOStructPtr->GPIO_Pin % 8))); + GPIOStructPtr->GPIO->ODR &= (0x0 << GPIOStructPtr->GPIO_Pin); + break; + + case In_PullUp: + GPIOStructPtr->GPIO->CRH &= ~(0xF << (4 * (GPIOStructPtr->GPIO_Pin % 8))); + GPIOStructPtr->GPIO->CRH |= (0x8 << (4 * (GPIOStructPtr->GPIO_Pin % 8))); + GPIOStructPtr->GPIO->ODR |= (0x1 << GPIOStructPtr->GPIO_Pin); + break; + + case In_Floating: + case In_Analog: + case Out_Ppull: + case Out_OD: + case AltOut_Ppull: + case AltOut_OD: + GPIOStructPtr->GPIO->CRH &= ~(0xF << (4 * (GPIOStructPtr->GPIO_Pin % 8))); + GPIOStructPtr->GPIO->CRH |= (GPIOStructPtr->GPIO_Conf << (4 * (GPIOStructPtr->GPIO_Pin % 8))); + break; + } + } + else { + switch (GPIOStructPtr->GPIO_Conf) { + case In_PullDown: + GPIOStructPtr->GPIO->CRH &= ~(0xF << (4 * (GPIOStructPtr->GPIO_Pin))); + GPIOStructPtr->GPIO->CRH |= (0x8 << (4 * (GPIOStructPtr->GPIO_Pin))); + GPIOStructPtr->GPIO->ODR &= (0x0 << GPIOStructPtr->GPIO_Pin); + break; + + case In_PullUp: + GPIOStructPtr->GPIO->CRL &= ~(0xF << (4 * (GPIOStructPtr->GPIO_Pin))); + GPIOStructPtr->GPIO->CRL |= (0x8 << (4 * (GPIOStructPtr->GPIO_Pin))); + GPIOStructPtr->GPIO->ODR |= (0x1 << GPIOStructPtr->GPIO_Pin); + break; + + case In_Floating: + case In_Analog: + case Out_Ppull: + case Out_OD: + case AltOut_Ppull: + case AltOut_OD: + GPIOStructPtr->GPIO->CRL &= ~(0xF << (4 * (GPIOStructPtr->GPIO_Pin))); + GPIOStructPtr->GPIO->CRL |= (GPIOStructPtr->GPIO_Conf << (4 * (GPIOStructPtr->GPIO_Pin))); + break; + } + } +} + +int MyGPIO_Read(GPIO_TypeDef * GPIO, char GPIO_Pin) { + return ((GPIO->IDR & (0x1 << GPIO_Pin)) >> GPIO_Pin); +} + +void MyGPIO_Set(GPIO_TypeDef * GPIO, char GPIO_Pin) { + GPIO->ODR |= (0x1 << GPIO_Pin); +} + +void MyGPIO_Reset(GPIO_TypeDef * GPIO, char GPIO_Pin) { + GPIO->ODR &= (0x0 << GPIO_Pin); +} + +void MyGPIO_Toggle(GPIO_TypeDef * GPIO, char GPIO_Pin) { + if (MyGPIO_Read(GPIO, GPIO_Pin) == 0x1) { + MyGPIO_Reset(GPIO, GPIO_Pin); + } + else { + MyGPIO_Set(GPIO, GPIO_Pin); + } +} diff --git a/driver-algu/src/timer.c b/driver-algu/src/timer.c new file mode 100644 index 0000000..768cc8b --- /dev/null +++ b/driver-algu/src/timer.c @@ -0,0 +1,192 @@ +#include "timer.h" +#include "gpio.h" + +void plantage(void) { + while(1); +} +void (*IT_Tim1) (void) = plantage; +void (*IT_Tim2) (void) = plantage; +void (*IT_Tim3) (void) = plantage; +void (*IT_Tim4) (void) = plantage; + +void MyTimer_Base_Init(MyTimer_Struct_Typedef * Timer) { + if ((Timer->Timer) == TIM1) + RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; + if ((Timer->Timer) == TIM2) + RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; + if ((Timer->Timer) == TIM3) + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; + if ((Timer->Timer) == TIM4) + RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; + + Timer->Timer->PSC = Timer->PSC; + Timer->Timer->ARR = Timer->ARR; +} + +void MyTimer_ActiveIT(TIM_TypeDef * Timer, char Prio, void (*IT_function) (void)) { + Timer->DIER |= TIM_DIER_UIE; + if (Timer == TIM2) { + NVIC_EnableIRQ(TIM1_BRK_IRQn); + NVIC_SetPriority(TIM1_BRK_IRQn, Prio); + IT_Tim1 = IT_function; + } + if (Timer == TIM2) { + NVIC_EnableIRQ(TIM2_IRQn); + NVIC_SetPriority(TIM2_IRQn, Prio); + IT_Tim2 = IT_function; + } + if (Timer == TIM3) { + NVIC_EnableIRQ(TIM3_IRQn); + NVIC_SetPriority(TIM3_IRQn, Prio); + IT_Tim3 = IT_function; + } + if (Timer == TIM4) { + NVIC_EnableIRQ(TIM4_IRQn); + NVIC_SetPriority(TIM4_IRQn, Prio); + IT_Tim4 = IT_function; + } +} + +void TIM1_IRQHandler(void) { + TIM1->SR &= ~TIM_SR_UIF; + (*IT_Tim1)(); +} + +void TIM2_IRQHandler(void) { + TIM2->SR &= ~TIM_SR_UIF; + (*IT_Tim2)(); +} + +void TIM3_IRQHandler(void) { + TIM3->SR &= ~TIM_SR_UIF; + (*IT_Tim3)(); +} + +void TIM4_IRQHandler(void) { + TIM4->SR &= ~TIM_SR_UIF; + (*IT_Tim4)(); +} + +void MyTimer_PWM(TIM_TypeDef * Timer ,char Channel) +{ + MyGPIO_Struct_TypeDef PWM_OUT; + PWM_OUT.GPIO_Conf = AltOut_Ppull; + switch (Channel) { + case 1: + case 2: + Timer->CCMR1 &= ~TIM_CCMR1_OC1M_0; + Timer->CCMR1 |= (TIM_CCMR1_OC1M_1| TIM_CCMR1_OC1M_2); + break; + + case 3: + case 4: + Timer->CCMR2 &= ~TIM_CCMR1_OC1M_0; + Timer->CCMR2 |= (TIM_CCMR1_OC1M_1| TIM_CCMR1_OC1M_2); + break; + } + + Timer->CCER |= (TIM_CCER_CC1E << (4*(Channel-1))); + +if(Timer == TIM1) + { + TIM1->BDTR |= 0x8000; + PWM_OUT.GPIO = GPIOA; + switch (Channel) { + case 1: + PWM_OUT.GPIO_Pin = 8; + break; + case 2: + PWM_OUT.GPIO_Pin = 9; + break; + case 3: + PWM_OUT.GPIO_Pin = 10; + break; + case 4: + PWM_OUT.GPIO_Pin = 11; + break; + } + } + if(Timer == TIM2) + { + PWM_OUT.GPIO = GPIOA; + switch (Channel) { + case 1: + PWM_OUT.GPIO_Pin = 0; + break; + case 2: + PWM_OUT.GPIO_Pin = 1; + break; + case 3: + PWM_OUT.GPIO_Pin = 2; + break; + case 4: + PWM_OUT.GPIO_Pin = 3; + break; + } + } + + if(Timer == TIM3) + { + switch (Channel) { + case 1: + PWM_OUT.GPIO = GPIOA; + PWM_OUT.GPIO_Pin = 6; + break; + case 2: + PWM_OUT.GPIO = GPIOA; + PWM_OUT.GPIO_Pin = 7; + break; + case 3: + PWM_OUT.GPIO = GPIOB; + PWM_OUT.GPIO_Pin = 0; + break; + case 4: + PWM_OUT.GPIO = GPIOB; + PWM_OUT.GPIO_Pin = 1; + break; + } + } + + if(Timer == TIM4) + { + PWM_OUT.GPIO = GPIOB; + switch (Channel) { + case 1: + PWM_OUT.GPIO_Pin = 6; + break; + case 2: + PWM_OUT.GPIO_Pin = 7; + break; + case 3: + PWM_OUT.GPIO_Pin = 8; + break; + case 4: + PWM_OUT.GPIO_Pin = 9; + break; + } + } + MyGPIO_Init(&PWM_OUT); +} + +void MyTimer_DutyCycle(TIM_TypeDef * Timer, char Channel, unsigned char DutyCycle) +{ + unsigned int RC; + RC = ((Timer->ARR)/100)*(DutyCycle); + switch (Channel) { + case 1: + Timer->CCR1 = RC; + break; + + case 2: + Timer->CCR2 = RC; + break; + + case 3: + Timer->CCR3 = RC; + break; + + case 4: + Timer->CCR4 = RC; + break; + } +} \ No newline at end of file diff --git a/driver-siyo/gpiodriver.c b/driver-siyo/gpiodriver.c new file mode 100644 index 0000000..3228fc7 --- /dev/null +++ b/driver-siyo/gpiodriver.c @@ -0,0 +1,70 @@ +#include "gpiodriver.h" + +void MyGPIO_Init(MyGPIO_Struct_TypeDef * GPIOStructPtr) +{ + RCC->APB2ENR |= GPIO2Int(GPIOStructPtr->GPIO); + //We get the pointer of the CRH/CRL depending on the IO_Pin number + volatile uint32_t * CRAny = GPIOStructPtr->GPIO_Pin >= 0x08 ? &(GPIOStructPtr->GPIO->CRH):&(GPIOStructPtr->GPIO->CRL); + //setup high or low + *CRAny &= ~(0xF << (GPIOStructPtr->GPIO_Pin%8)*4); //reset + //for input pull or push + switch(GPIOStructPtr->GPIO_Conf) + { + case In_PullUp: + GPIOStructPtr->GPIO->ODR |= (0x01 << GPIOStructPtr->GPIO_Pin); //if pullup -> ODR = 1 + *CRAny |= (In_PullDown << (GPIOStructPtr->GPIO_Pin%8)*4); //set pin mode -> force to In_PullDown because PullDown is modified + break; + case In_PullDown: + GPIOStructPtr->GPIO->ODR &= ~(0x01 << GPIOStructPtr->GPIO_Pin); //if pullup -> ODR = 0 + default: + *CRAny |= (GPIOStructPtr->GPIO_Conf << (GPIOStructPtr->GPIO_Pin%8)*4); //set pin mode for any input/output + break; + } +} + +int MyGPIO_Read(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin) +{ + return (GPIO->IDR & (0x1 << GPIO_Pin)) > 0; +} + +void MyGPIO_Set(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin) +{ + GPIO->BSRR = (1 << GPIO_Pin); //BSX set register +} + +void MyGPIO_Reset(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin) +{ + GPIO->BRR = (1 << GPIO_Pin); //BRX = BSX+16 reset register +} + +void MyGPIO_Toggle(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin) +{ + if((GPIO->ODR = GPIO->ODR & (1 << GPIO_Pin)) > 0) + { + GPIO->BRR = (1 << GPIO_Pin); //reset + } else { + GPIO->BSRR = (1 << GPIO_Pin); //set + } +} + +int GPIO2Int(GPIO_TypeDef * GPIOX) +{ + if(GPIOX == GPIOA) + { + return (0x01 << 2); + } else if (GPIOX == GPIOB){ + return (0x01 << 3); + } else if (GPIOX == GPIOC){ + return (0x01 << 4); + } else if (GPIOX == GPIOD){ + return (0x01 << 5); + } else if (GPIOX == GPIOE){ + return (0x01 << 6); + } else if (GPIOX == GPIOF){ + return (0x01 << 7); + } else if (GPIOX == GPIOE){ + return (0x01 << 8); + } else { + return -1; + }; +} diff --git a/driver-siyo/gpiodriver.h b/driver-siyo/gpiodriver.h new file mode 100644 index 0000000..65a297c --- /dev/null +++ b/driver-siyo/gpiodriver.h @@ -0,0 +1,28 @@ +#ifndef GPIODRIVER_H +#define GPIODRIVER_H +#include "stm32f10x.h" + +typedef struct +{ + GPIO_TypeDef * GPIO; //GPIO A,B,C,D... + uint8_t GPIO_Pin; //numero de 0 à 15 + uint8_t GPIO_Conf; //voir ci dessous +} MyGPIO_Struct_TypeDef; + +#define In_Floating 0x04 +#define In_PullDown 0x08 +#define In_PullUp 0xF8 +#define In_Analog 0x00 +#define Out_PullUp 0x01 +#define Out_OD 0x05 +#define AltOut_Ppull 0x09 +#define AltOut_OD 0x0d + +int GPIO2Int(GPIO_TypeDef * GPIOX); +void MyGPIO_Init(MyGPIO_Struct_TypeDef * GPIOStructPtr); +int MyGPIO_Read(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin); +void MyGPIO_Set(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin); +void MyGPIO_Reset(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin); +void MyGPIO_Toggle(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin); + +#endif diff --git a/driver-siyo/timerdriver.c b/driver-siyo/timerdriver.c new file mode 100644 index 0000000..0dd11ca --- /dev/null +++ b/driver-siyo/timerdriver.c @@ -0,0 +1,162 @@ +#include "timerdriver.h" + +void (* pFnc) (void); /* déclaration d’un pointeur de fonction */ + +void Init_Periph (void (* ptrFonction)(void)) +{ + pFnc = ptrFonction; /* affectation du pointeur */ +} + +void MyTimer_Base_Init(MyTimer_Struct_TypeDef * Timer) +{ + //TIM1 uses the APB2ENR register from RCC. The others uses the APB1ENR, so we check this value. + if(Timer->Timer == TIM1) + { + RCC->APB2ENR |= TimerX2Int(Timer->Timer); + } else { + RCC->APB1ENR |= TimerX2Int(Timer->Timer); + } + Timer->Timer->ARR = Timer->ARR; + Timer->Timer->PSC = Timer->PSC; +} + +void MyTimer_ActiveIT(TIM_TypeDef * TimerX, uint8_t Prio) +{ + uint8_t positionTimerIT = TimerIT2UInt(TimerX); + TimerX->DIER |= (0x1<IP[positionTimerIT] |= (Prio << 0x4); + NVIC->ISER[0] |= (0x1<channel) + { + case 2: + PWM->Timer->CCMR1 |= (PWMMode_1<Timer->CCR2 = PWM->CCR; //Compare Capture register count + break; + case 3: + PWM->Timer->CCMR2 |= (PWMMode_1<Timer->CCR3 = PWM->CCR; + break; + case 4: + PWM->Timer->CCMR2 |= (PWMMode_1<Timer->CCR4 = PWM->CCR; + break; + default: + PWM->Timer->CCMR1 |= (PWMMode_1<Timer->CCR1 = PWM->CCR; + break; + } + PWM->Timer->CCER |= (1<<4*(PWM->channel-1)); //enable capture/compare registers +} + +MyGPIO_Struct_TypeDef GPIOFromPWM(MyPWM_Struct_TypeDef PWM) +{ + //use of C99 compound literal for return statement, may not work on C90. + if(PWM.Timer == TIM2) + { + //PA0 -> TIM2,CH1... iteration + return (MyGPIO_Struct_TypeDef){GPIOA,PWM.channel-1,AltOut_Ppull}; + } + else if(PWM.Timer == TIM3) + { + if(PWM.channel > 2) { + return (MyGPIO_Struct_TypeDef){GPIOB,PWM.channel-3,AltOut_Ppull}; //PB0 -> TIM3,CH3;PB1 -> TIM3,CH4 + } + else { + return (MyGPIO_Struct_TypeDef){GPIOA,PWM.channel+5,AltOut_Ppull}; //PA6 -> TIM3,CH1;PA7 -> TIM3,CH2 + } + } + else if(PWM.Timer == TIM4) + { + return (MyGPIO_Struct_TypeDef){GPIOB,PWM.channel+5,AltOut_Ppull}; //PB6 -> TIM4,CH1... iteration + } + else { //TIM1 case + return (MyGPIO_Struct_TypeDef){GPIOA,PWM.channel+7,AltOut_Ppull};//PA8 -> TIM1,CH1... iteration + } +} + +int TimerX2Int(TIM_TypeDef * TimerX) +{ + if(TimerX == TIM1) + { + return (0x01 << 11); + } else if (TimerX == TIM2){ + return (0x01 << 0); + } else if (TimerX == TIM3){ + return (0x01 << 1); + } else if (TimerX == TIM4){ + return (0x01 << 2); + } /*else if (TimerX == TIM5){ + return (0x01 << 3); + } else if (TimerX == TIM6){ + return (0x01 << 4); + } else if (TimerX == TIM7){ + return (0x01 << 5); + } else if (TimerX == TIM8){ + return (0x01 << 13); + } else if (TimerX == TIM9){ //For now we dont do timer > 4 + return (0x01 << 19); + } else if (TimerX == TIM10){ + return (0x01 << 20); + } else if (TimerX == TIM11){ + return (0x01 << 21); + } else if (TimerX == TIM12){ + return (0x01 << 6); + } else if (TimerX == TIM13){ + return (0x01 << 7); + } else if (TimerX == TIM14){ + return (0x01 << 8); + }*/ else { + return -1; + }; +} + +uint8_t TimerIT2UInt(TIM_TypeDef * TimerX) +{ + if(TimerX == TIM1) + { + return TIM1_CC_IRQn; + } else if(TimerX == TIM2) + { + return TIM2_IRQn; + } else if(TimerX == TIM3) + { + return TIM3_IRQn; + } else if(TimerX == TIM4) + { + return 30; + } else { + return 0; + } +} + +void TIM1_CC_IRQHandler(void) +{ + if (pFnc != 0) + (*pFnc) (); /* appel indirect de la fonction */ + TIM1->SR &= ~(0x1<SR &= ~(0x1<SR &= ~(0x1<SR &= ~(0x1< TIM4 + unsigned short ARR; + unsigned short PSC; +} MyTimer_Struct_TypeDef; + +typedef struct { + TIM_TypeDef * Timer; //TIM1 -> TIM4 + uint8_t channel; + uint16_t CCR; +} MyPWM_Struct_TypeDef; + +void MyTimer_Base_Init(MyTimer_Struct_TypeDef * Timer); +int TimerX2Int(TIM_TypeDef * TimerX); +uint8_t TimerIT2UInt(TIM_TypeDef * TimerX); +void MyTimer_ActiveIT(TIM_TypeDef * TimerX, uint8_t Prio); +void Init_Periph (void (* ptrFonction)(void)); +void MyTimer_PWM_Init(MyPWM_Struct_TypeDef * PWM); +MyGPIO_Struct_TypeDef GPIOFromPWM(MyPWM_Struct_TypeDef PWM); + +#define MyTimer_Base_Start(Timer) (Timer->CR1 |= (0x01<CR1 &= ~(0x01<BDTR |= (1<BDTR &= ~(1<vt#I5Tx>`wVYeANl z)ymj}CW07{oiv4{ot8A6x=cEqPCG4SAk&h9F|^Z^c3P{U9R@NT73hT4WJV0i#6y|7 z-~XR;ckiwwYzPVI<9Kw>`TqAg_w2dnp8xv#o0Hk$(Ob&5TE!*gfU51hT2}M+CM_{o zPDED`nVUY`--azjAN-d{Bqxt15{YezeJ5g#(Zq1#@W_rGO(UTu5EFf!2g9v&S($kE zkNsT2W71HihE}qM#$B$4RCpxp) ziLA!4@pMi%d#7wsXUy^5824*OvN=4oqjBkeEh$sduO(#AueRY_`dA7)#K02Ku~agf z*dLE;tixkgUn)7Gsqxf!p_vo$@}noxjl&HS`DqevZEX#0ZwiGm4V*J0914MBS=*a- zG^z)D?4nP4x=Zusooeb8gFx+TBf~)4K!D z64munL|o(YQ?Y-jV1NGUimqEn>+Wsc|3tfMmTqV{a0?=$8=6tm*@sSh=1q^;@ZNdP zOxMEnG0(K386E=d!P8eCKSrJhY&k_M`?A8*BID9rw;-`{*fYJHHDjaqLYHT;MgN?# z8BtbFS7k=l#nu{I-u=F3=7xo7SS;nU2SU8_7*BGHr_tr^zQ5g^b#>G6%x=E^=MS9x z`hTBqb9YsBUDfq&ciG^(-P7sFypP_A%_QIHKG|M7OV&K@)epO$Pe&Fga3S{Hq{n(Y z<{R|N_3dtM*Upi30a9;>)HMAoq{^)~z^Sla$MyAY`V`myvZrSBrB%j-zU)5+e)qx) z=GUou{Wl`7?p;0l;wrijpL{KF=E94v-=XRa--)b={`1~zN3R|Idi3QzwWBKs|6!4? z7rKADNY^X6e=WLeqJM>Y&EWIh#&N@%iJXmWd+hV8+UHlq=fjI+*yn@V z=aZPz{{;`0`pE_#_dKK14y>dC$E!wo= zH9Cub^VgaDn{D@hjm&rE*1vF(YM8E`MYPHNTDf;+RoR}E{hqmUZ(WsZ56xG*uD$N% zemq&;q`B2Uq&d64&N>8e3B{Gn9vvROiH!TIYFCh#yoT5Gx_oY5na|_%`g}gWuiRJR zt@Kq9RXPl~(f)a`;aMUM^F#J!{YSJ>=NJzQ?Y5O)IB9;>STrt$czmYs3dWZ0mX2+~ z#`5=Pts|aSTtw|F?>*^xu*YRj_b;7J|cbm{K>Kh-4D4QW{W?0oUeaOHl6pP zPi$W9UM%0|Dz81ba9$wJSQ2&83dl?`r}+3>=?0oIBXn3p6p6%S`2VH4ID)-I*HBO%CYYHdx0F zr;bjHq;?&i$PTBixk^_5F>9GOyeV{iveAnavei{SOeeqa)prv73LrAwV z0aF99@!_#4jQr(Hh(#U1@#Be(uHJ#hh9=n3vE}V_Bodtm+j^{eG;TW>i^mS^PaN#* z<9b(16MEQ@K$jAz?d}{(?CV&Lyzhh_E({^wx*LZ1M_*EMSX&Flpki#6U{?ut)7{YL zHA)qC3BRm_Usl5R2%pzYRXinpukZ_Nn74%Q6Fxs5RPmMY{le$9UKM`{zq|xjh`eQs zQw62+wwYL2f>%?YgYTwyE_G?ldkPoc%y$-HlR_Hvv)+Y&cIgnj!iJ5zB9!h6oc1Jh0a=D;p0E8&;X_lo$Q626Dd74f|#d@ns! z#P^l(ee`${-(SM_)2|ls%S-s>^eFf&vYv;7%IV%B`HB+x3c63rTOwaUIW5m~&V~D3 zJU*3lm*#V2fIp=5ZG1Z#0r2?#Grye~x)|WxScGe+x(L_Ok8EMo2Cbymif|pBE5cXN z?-${#=~s&IDursHvv^ z2wdsL&i!hhN~ZY`)#g_Kx9&|}Em4_CKj4$9e}WWFm{`{HI`O!&o>5DNmtG|LHW@}O zCbh{&RId=>$134|i~KyFRYAR8>AjaHTte#|I)tm)Ofa4w46pE4YrIWkoazc67vXQ!c!$O}XpFs!@NsG^@}JRov&LWwKdA98 zjV+CD(HLV)4S3!)By%{39h%CeCaGaEm(3-IP>}=>~OZ zTR53@Qsr#aNx)gJKHDv!>Jwl^UE-)X&nP`sZovLg;v7~RI%>eKG=VK&Vic#bICpNq zel|(zhD2ij!B{jAPvv^E>4|JQccMV-98V67rEpk{K4p(5u*J-A?~YB57TV!f)h28n zg2BGj-BYQ_Trdc4W9cDv>dnXBd<^b9oJLM((gC$4POIXoI_qc6|BiT&C zd1r!+e5k)Pr)gPEXgN-J+p?VIWjW#HINO(Fv`}v@+cliinS!jO3~;;A_;B}d@tm|N zG9PVFn2QdIo`>m%CFWo|zYw+Med!U~BLT@&3Khy&Vc}1MKbz9*Fn0 zMLUC??QPqGeVw;%5BBzT#${6`-#>nK3`cKJ;bw66*qm8 z8y>**;)7ct$$vk*lj?eRiAC)8K?s$+54#z6Ac(W@fh;OB8(t`4LQ z2&3A#xQpTvY~~dgC>VzvBoAlWpi1TFOOu9FVA$FgEV>+R=3WM zNfzEscS7ne__7u<+W3zt?ERtk3KZA^|Z+a*2HuNhnyG?QCw^NI7ngmCH!-A{lw&o?a2<0X%5u#0k zH)?E9Q1AwgO|k@Er}P(SaIN5L6`r4_)q+g6A3^%u=g9VS%p?LTKGQWYz5l2 zr_6cNG&f(I^#VNti)ET>n6w!dfxdQX*0#v;!k!2H@Ziq4W&>84n#Gu#j#=!S!{{8Z zCja|$rdO7uT)V`0ICGS~W%8WPMRN{ITiePne&jqN@2~CBfkx^5xsrICHo890#+8kW z{U-B&B~K_%B;=tkpC{ZF`k$RAl%D>~^Mv;JE|Di>*8k@Te-845_JoPpVu^1JSBXu@Oj--#aqJn37^+_Reba( zMg8%Y;9B~ogU@-kM>OUwH0Sl~JetBL-K+V0*04CQS9ty87+u8YOR6YbNuwqH-pG#y zA;-VE9RF`eG%VN!uJ%N>bP+BQLOK!K#{($gzuwr z%~#{)FX8)<$te_rR&XXLUks|E=kkbON~(*Fv^cM3zn-v|f#j69!~zsSe%DxagisF!c$odo%g-bpCRBNcyye}(y<%b!9oo!2RR{qIcKa0n&;R&m7Qxg#&zpKsA$qG=x`;}Z+pMQ=gE(LtBPu^azkM-_wDTokPGs$k#2eRuIC zUn2PyH=g8hRdLx3rgYH84jVgbmrevgX2z!HEy(dXo*BwgUf+>P_&ZxiIupnvhY8St zV5N|9u*YR%QAb!=^mr7D4KNFZ#f5PO-6@d~IzkkaZvwH$;!sRC4ig)x>_i#rJ@O7N4x>SLADT{ z=R~><-SmVBN;3Gl~=y6~*xk*Z2;`FP`h)@vF2JGDGa*D5oT|fn){6uzDRp+p6%~PC>UlJg5jtn(}`Fk!&xjHn|Y$W<`GQNQ* literal 0 HcmV?d00001 diff --git a/driver/MyI2C.h b/driver/MyI2C.h new file mode 100644 index 0000000..519965c --- /dev/null +++ b/driver/MyI2C.h @@ -0,0 +1,229 @@ +#ifndef _I2C_ +#define _I2C_ + +#include "stm32f10x.h" + +/************************************************************************************* +===================== By Periph team INSA GEI 2022 =========================== +*************************************************************************************/ + +/* +************************************************************************************* +===================== I2C les IO STM32F103 ================================= +************************************************************************************* + +Les IO sont pris en charge par la lib, pas besoin de faire les configurations Alt OD. + +**I2C1** +SCL PB6 +SDA PB7 + +**I2C2** +SCL PB10 +SDA PB11 + + +************************************************************************************* +==================== Fondamentaux I2C ========================================== +************************************************************************************* +- Bus synchrone Low speed (<100kHz) ou high speed (=400kHz), Ici Low speed 100kHz. +- Transfert octet par octet, poids fort en premier, avec aquittement pour chaque octet +- Deux lignes SDA et SCL (horloge) en open drain, repos '1' +- bit "normal" = SDA stable lors du pulse SCL (ie durant l'état haut de SCL, SDA est stable) +- bit Start/Stop/Restart = SDA non stable lorsque SCL vaut '1' (violation règle précédente) + * Start : front descendant de SDA lorsque SCL vaut '1' + * Stop : front montant de SDA lorsque SCL = '1' + * Restart = Start en cours de trame (typiquement pour changer Write/read). +- uC en Mode Master uniquement (c'est notre choix) : c'est le uC qui est maître de l'horloge SCL. +- Le Slave a une @ 7 bits. On ajoute un bit LSB qui est /WR (donc 0 pour écriture, 1 pour lecture) +- Une adresse s'écrit donc |a6 a5 a4 a3 a2 a1 a0 /WR| ce qui donne 8 bits. Elle indique une future +lecture ou écriture. +On parle d'@ 7 bits en regroupant |a6 a5 a4 a3 a2 a1 a0| +On parle d'@ 8 bits en regroupant |a6 a5 a4 a3 a2 a1 a0 /WR| (donc une @ écriture, une @ lecture) +NB : préférer le concept @7bits...c'est plus clair. + +- On peut lire ou écrire une ou plusieurs données à la suite. C'est lors de l'envoie de l'adresse Slave +par le Master que le sens à venir pour les datas est indiqué. +- En écriture, + * les Ack sont faits par le slave après chaque octet envoyé par le master (Ack = mise à 0 le bit 9). +- En lecture, + * dès que le l@ slave est transmise (/RW = 1), et le Ack réalisé, le slave positionne le bit 7 + du prochain octet à lire sur SDA par anticipation , + * le master enchaîne ses pulses (9), lors du pulse 9 (le dernier) c'est le master qui acquite. + * Après chaque acquitement, le Slave amorce le prochain octet en positionnant son bit 7 sur SDA + * Après le dernier octet, le Master génère un stop. + * Pour pouvoir générer le stop, le Master doit piloter SDA, or ce n'est pas possible puisque + le Slave positionne le futur bit 7 ... Pour régler ce problème : + lors du dernier transfert, le Master N'acquitte PAS (NACK). Ainsi le Slave ne + propose plus le bit 7 du prochain octet sur SDA et libère SDA. Le Master peut alors clôturer la + communication avec un Stop. + + + + +======= Echange typique avec un Slave ================================================================ +- Une lecture ou écriture se fait vers un Slave et à partir d'une adresse mémoire donnée (pointeur interne). +Ce pointeur est automatiquement incrémenté dans le slave lors des accès écriture ou lecture. + +- Ecriture de N octets , trame complète (@ = adresse slave, pt = valeur de chargement du pointeur interne) +|Start Cond |@6|@5|@4|@3|@2|@1|@0| Wr =0 |Slave ACK| +|pt7|pt6|pt5|pt4|pt3|pt2|pt1|pt0|Slave ACK| +|d7|d6|d5|d4|d3|d2|d1|d0|Slave ACK| (data 1) +..... +|d7|d6|d5|d4|d3|d2|d1|d0|Salve ACK|Stop Cond| (data N) + +- Lecture de N octets à partir d'une adresse de pointeur donnée +|Start Cond |@6|@5|@4|@3|@2|@1|@0| Wr =0 |Slave ACK| +|pt7|pt6|pt5|pt4|pt3|pt2|pt1|pt0|Slave ACK| +|ReStart Cond |@6|@5|@4|@3|@2|@1|@0| Wr =1 |Slave ACK| (NB: restart nécessaire pour changer écriture / lecture) +|d7|d6|d5|d4|d3|d2|d1|d0|Master ACK| (data 1) +..... +|d7|d6|d5|d4|d3|d2|d1|d0|Master ACK| (data N-1) +|d7|d6|d5|d4|d3|d2|d1|d0|Master NACK|Stop Cond| (data N) + + + + + +************************************************************************************* +==================== La lib I2C ========================================== +************************************************************************************* + +3 fonctions essentielles : +MyI2C_Init +MyI2C_PutString +MyI2C_GetString + +1 fonction spéciale : MyI2C_Get_Error + +Les fonctions Put/Get string fonctionnent sur le principe classique décrit précédemment +(Slave@, Pter @, Data...). +La fonction init prend parmi ses paramètres le nom d'une fct callback d'erreur. +En fait, le driver gère en IT les erreurs possibles I2C. La fonction MyI2C_Get_Error permet de +recevoir un code erreur. +Il est conseillé d'utiliser ce callback. Si on tombe dedans, c'est qu'une erreur s'est produite. +Si le code erreur est "inconnu", souvent c'est qu'il y a un soucis à l'adressage slave: +Vérifier alors la connectique physique SDA/SCL ainsi que l'alimentation du slave ou tout simplement +l'@ slave ! + + +==========================================================================================*/ + + + + + +/*========================================================================================= + GESTION ERREURS +========================================================================================= */ +typedef enum +{ + OK, + BusError, // + AckFail, // Pas,d'ack + TimeOut, // SCL est resté plus de 25ms à l'état bas + UnknownError // IT erreur déclenchée mais pas de flag explicite ... +} MyI2C_Err_Enum; + + + + +/** + * @brief Retourne les erreurs I2C + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @retval Type d'erreur rencontrée , voir MyI2C_Err_Enum + */ + +MyI2C_Err_Enum MyI2C_Get_Error(I2C_TypeDef * I2Cx); + + + +/*========================================================================================= + INITIALISATION I2C +========================================================================================= */ + + +/** + * @brief Initialise l'interface I2C (1 ou 2) + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param char IT_Prio_I2CErr 0 à 15 (utilisé en cas d'erreur, IT courte et non bloquante + * @param *ITErr_function : callback à utiliser pour sortir d'un plantage transmission + * @retval None + * @Example MyI2C_Init(I2C1, 2,My_CallbackErr); + + + + */ +void MyI2C_Init(I2C_TypeDef * I2Cx, char IT_Prio_I2CErr, void (*ITErr_function) (void)); + + + +/*========================================================================================= + EMISSION I2C : PutString +========================================================================================= */ + + +// Structure de données pour l'émission ou la réception I2C : +typedef struct +{ + char SlaveAdress7bits; // l'adresse I2C du slave device + char * Ptr_Data; // l'adresse du début de tableau char à recevoir/émettre (tableau en RAM uC) + char Nb_Data; // le nbre d'octets à envoyer / recevoir +} +MyI2C_RecSendData_Typedef; + + + +/** + * @brief|Start Cond |@6|@5|@4|@3|@2|@1|@0| Wr =0 |Slave ACK| + |pt7|pt6|pt5|pt4|pt3|pt2|pt1|pt0|Slave ACK| + |d7|d6|d5|d4|d3|d2|d1|d0|Slave ACK| (data 1) + ..... + |d7|d6|d5|d4|d3|d2|d1|d0|Salve ACK|Stop Cond| (data N) + + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param PteurAdress = adresse de démarrage écriture à l'interieur du slave I2C + * @param DataToSend, adresse de la structure qui contient les informations à transmettre + voir définition MyI2C_RecSendData_Typedef + * @retval None + * @Example MyI2C_PutString(I2C1,0xAA, &MyI2C_SendTimeData); + * Ecrit dans le slave câblé sur I2C1 à partir de l'@ mémoire interne Slave 0xAA + + */ +void MyI2C_PutString(I2C_TypeDef * I2Cx, char PteurAdress, MyI2C_RecSendData_Typedef * DataToSend); + + + + + + + + + + +/*========================================================================================= + Réception I2C : GetString +========================================================================================= */ + +/** + * @brief |Start Cond |@6|@5|@4|@3|@2|@1|@0| Wr =0 |Slave ACK| + |pt7|pt6|pt5|pt4|pt3|pt2|pt1|pt0|Slave ACK| + |ReStart Cond |@6|@5|@4|@3|@2|@1|@0| Wr =1 |Slave ACK| + |d7|d6|d5|d4|d3|d2|d1|d0|Master ACK| (data 1) + ..... + |d7|d6|d5|d4|d3|d2|d1|d0|Master NACK|Stop Cond| (data N) + + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param PteurAdress = adresse de démarrage lecture à l'interieur du slave I2C + * @param DataToSend, adresse de la structure qui contient les informations nécessaires à la + réception des données voir définition MyI2C_RecSendData_Typedef + * @retval None + * @Example MyI2C_GetString(I2C1,0xAA, &MyI2C_RecevievedTimeData); + Lit dans le slave câblé sur I2C1 à partir de l'@ mémoire interne Slave 0xAA + */ +void MyI2C_GetString(I2C_TypeDef * I2Cx, char PteurAdress, MyI2C_RecSendData_Typedef * DataToReceive); + + + + +#endif diff --git a/driver/MySPI.h b/driver/MySPI.h new file mode 100644 index 0000000..560404c --- /dev/null +++ b/driver/MySPI.h @@ -0,0 +1,129 @@ + +#ifndef INC_MYSPI_H_ +#define INC_MYSPI_H_ + +#include "stm32f10x.h" + +/************************************************************************************* +===================== By Periph team INSA GEI 2022 =========================== +*************************************************************************************/ + +/* +************************************************************************************* +===================== I2C les IO STM32F103 ================================= +************************************************************************************* +Les IO sont pris en charge par la lib, pas besoin de faire les configurations + + +Sur la Nucléo , le SPI1 est perturbé par la LED2 (PA5), mais doit pouvoir subir les front SCK qd même (LED clignote vite..) +le SPI2 n'est pas utilisable car pin non connectées par défaut (sauf à modifier les SB). En fait la Nucléo fait un choix entre SPI1 +et SPI2 par soudage jumper (SB). + +-> Utiliser SPI1 avec la carte Nucléo + + * **IO SPI 1** + SPI1_NSS PA4 + SPI1_SCK PA5 + SPI1_MISO PA6 + SPI1_MOSI PA7 + + **IO SPI 2** + SPI2_NSS PB12 + SPI2_SCK PB13 + SPI2_MISO PB14 + SPI2_MOSI PB15 + + + + + +************************************************************************************* +==================== Fondamentaux SPI ========================================== +************************************************************************************* +- Bus Synchrone, 4 fils (même si on peut l'utiliser en 3 fils) +- Transfert à l'octet +- Protocole entre un Master (contrôle SCK) et un Slave +- SCK permet de synchroniser les bits de chaque octet. Il se configure par : + * son niveau de repos : ici niveau '1' + * le front actif de synchronisation pour chaque bit : ici front montant (front up durant bit stable) +- /CS ou /NSS active le slave sur l'état bas +- MOSI : Master Out Slave In (donc data circulant du Master vers le Slave, donc écriture dans le Slave) +- MISO : Master In Slave Out (donc data circulant du Slave vers le Master, donc lecture du Slave) + +Bien que la lib propose une fonction d'écriture et de lecture : + * une écriture s'accompagne obligatoirement d'une lecture (bidon) + * une lecture s'accompagne obligatoirement d'une écriture (bidon) +La gestion /CS = /NSS se fait "à la main". On peut alors lire toute une série d'octets +en laissant /CS à l'état bas pendant toute la durée de circulation des octets. + + +************************************************************************************* +==================== La lib SPI ========================================== +************************************************************************************* + +fonctions essentielles : + +MySPI_Init +MySPI_Send +MySPI_Read +MySPI_Set_NSS +MySPI_Clear_NSS + + +==========================================================================================*/ + + + + +/*========================================================================================= + INITIALISATION SPI +========================================================================================= */ + +/** + * @brief Configure le SPI spécifié : FSCK = 281kHz, Repos SCK = '1', Front actif = up + Gestion /CS logicielle à part, configure les 4 IO + - SCK, MOSI : Out Alt push pull + - MISO : floating input + - /NSS (/CS) : Out push pull + * @param SPI_TypeDef * SPI : SPI1 ou SPI2 + */ +void MySPI_Init(SPI_TypeDef * SPI); + + + +/** + * @brief Envoie un octet (/CS non géré, à faire logiciellement) + Plus en détail, émission de l'octet souhaité sur MOSI + Lecture en même temps d'un octet poubelle sur MISO (non exploité) + * @param : char ByteToSend : l'octet à envoyer + */ +void MySPI_Send(char ByteToSend); + + +/** + * @brief Reçoit un octet (/CS non géré, à faire logiciellement) + Plus en détail, émission d'un octet bidon sur MOSI (0x00) + pour élaborer les 8 fronts sur SCK et donc piloter le slave en lecture + qui répond sur MISO + * @param : none + * @retval : l'octet lu. + */ +char MySPI_Read(void); + + + +/** + * @brief Positionne /CS = /NSS à '1'. A utiliser pour borner les octets à transmettre/recevoir + * @param : none + */ +void MySPI_Set_NSS(void); + + + +/** + * @brief Positionne /CS = /NSS à '0'. A utiliser pour borner les octets à transmettre/recevoir + * @param :none + */ +void MySPI_Clear_NSS(void); + +#endif