| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- /*
- GPIO pulse generator project for the STM32L031
-
- I2C:
- Write 0, <gpio cmd>
-
- */
- #include "stm32l031xx.h"
- #include "core_cm0plus.h"
- /*================================================*/
- /* forward declaration */
- void setGPIO( uint8_t n );
- void clearGPIO(void);
- /*================================================*/
- /* queue */
- #define GPIO_QUEUE_MAX 128
- uint8_t gpio_queue_mem[GPIO_QUEUE_MAX];
- uint8_t gpio_queue_start = 0;
- uint8_t gpio_queue_end = 0;
- /* this is called from the I2C interrupt procedures */
- void addCmdToGPIOQueue(uint8_t n)
- {
- uint8_t pos;
- pos = gpio_queue_end ;
- pos++;
- if ( pos >= GPIO_QUEUE_MAX )
- pos = 0;
- if ( pos == gpio_queue_start )
- return; // queue overflow
- gpio_queue_mem[gpio_queue_end] = n;
- gpio_queue_end = pos;
- }
- uint8_t isGPIOQueueEmpty(void)
- {
- if ( gpio_queue_start == gpio_queue_end )
- return 1;
- return 0;
- }
- /* get the next command in the queue, return 255 if the queue is empty */
- uint8_t getCmdFromGPIOQueue(void)
- {
- uint8_t r = gpio_queue_mem[gpio_queue_start];
- if ( isGPIOQueueEmpty() )
- return 255;
- return r;
- }
-
- void removeCmdFromGPIOQueue(void)
- {
- if ( isGPIOQueueEmpty() )
- return;
- __disable_irq();
- gpio_queue_start++;
- if ( gpio_queue_start >= GPIO_QUEUE_MAX )
- gpio_queue_start = 0;
- __enable_irq();
- }
- /*================================================*/
- /* GPIO output state machine */
- #define GPIO_STATE_IDLE 0
- #define GPIO_STATE_TURN_ON 1
- #define GPIO_STATE_WAIT_ON 2
- #define GPIO_STATE_OFF 3
- /* time is in ticks + 1 */
- #define GPIO_STATE_ON_TICKS 0
- #define GPIO_STATE_OFF_TICKS 4
- volatile uint8_t gpio_state = GPIO_STATE_IDLE;
- volatile uint8_t gpio_state_machine_output_number = 0;
- volatile uint8_t gpio_state_machine_counter = 0;
- void gpioNextState(void)
- {
- switch(gpio_state)
- {
- case GPIO_STATE_IDLE:
- break;
- case GPIO_STATE_TURN_ON:
- setGPIO(gpio_state_machine_output_number);
- gpio_state_machine_counter = GPIO_STATE_ON_TICKS;
- gpio_state = GPIO_STATE_WAIT_ON;
- break;
- case GPIO_STATE_WAIT_ON:
- if ( gpio_state_machine_counter == 0 )
- {
- clearGPIO();
- gpio_state_machine_counter = GPIO_STATE_OFF_TICKS;
- gpio_state = GPIO_STATE_OFF;
- }
- else
- {
- gpio_state_machine_counter--;
- }
- break;
- case GPIO_STATE_OFF:
- if ( gpio_state_machine_counter == 0 )
- {
- gpio_state = GPIO_STATE_IDLE;
- }
- else
- {
- gpio_state_machine_counter--;
- }
- break;
- default:
- gpio_state = GPIO_STATE_IDLE;
- break;
- }
- }
- uint8_t gpioStartStateMachine(uint8_t gpio_number)
- {
- /* can we enable the state machine? */
- if ( gpio_state != GPIO_STATE_IDLE )
- return 0; /* not idle, can not start */
- /* set the gpio number */
- __disable_irq();
- gpio_state_machine_output_number = gpio_number;
- gpio_state = GPIO_STATE_TURN_ON;
- __enable_irq();
- return 1;
- }
- /*================================================*/
- /* Queue & State Machine Connector */
- void processQueue(void)
- {
- uint8_t cmd;
- cmd = getCmdFromGPIOQueue();
- if ( cmd < 255 )
- {
- /* try to start the state machine */
- if ( gpioStartStateMachine(cmd) != 0 )
- {
- /* success, remove the cmd from the queue */
- removeCmdFromGPIOQueue();
- }
- }
- }
- /*==============================================*/
- /* I2C */
- volatile unsigned char i2c_mem[256]; /* contains data, which read or written */
- volatile unsigned char i2c_idx; /* the current index into i2c_mem */
- volatile unsigned char i2c_is_write_idx; /* write state */
- volatile uint16_t i2c_total_irq_cnt;
- volatile uint16_t i2c_TXIS_cnt;
- volatile uint16_t i2c_RXNE_cnt;
- void i2c_mem_reset_write(void)
- {
- i2c_is_write_idx = 1;
- }
- void i2c_mem_init(void)
- {
- i2c_idx = 0;
- i2c_mem_reset_write();
- }
- void i2c_mem_set_index(unsigned char value)
- {
- i2c_idx = value;
- i2c_is_write_idx = 0;
- }
- void i2c_mem_write_via_index(unsigned char value)
- {
- if ( i2c_idx == 0 )
- {
- /* additionall put this byte into the queue */
- addCmdToGPIOQueue(value);
- }
- i2c_mem[i2c_idx++] = value;
- }
- unsigned char i2c_mem_read(void)
- {
- i2c_mem_reset_write();
- i2c_idx++;
- return i2c_mem[i2c_idx];
- }
- void i2c_mem_write(unsigned char value)
- {
- if ( i2c_is_write_idx != 0 )
- {
- i2c_mem_set_index(value);
- }
- else
- {
- i2c_is_write_idx = 0;
- i2c_mem_write_via_index(value);
- }
- }
- /* address: I2C address multiplied by 2 */
- /* Pins PA9 (SCL) and PA10 (SDA) */
- void i2c_hw_init(unsigned char address)
- {
- RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; /* Enable clock for I2C */
- RCC->IOPENR |= RCC_IOPENR_IOPAEN; /* Enable clock for GPIO Port A */
-
- __NOP(); /* extra delay for clock stabilization required? */
- __NOP();
- /* configure io */
- GPIOA->MODER &= ~GPIO_MODER_MODE9; /* clear mode for PA9 */
- GPIOA->MODER |= GPIO_MODER_MODE9_1; /* alt fn */
- GPIOA->OTYPER |= GPIO_OTYPER_OT_9; /* open drain */
- GPIOA->AFR[1] &= ~(15<<4); /* Clear Alternate Function PA9 */
- GPIOA->AFR[1] |= 1<<4; /* I2C Alternate Function PA9 */
-
- GPIOA->MODER &= ~GPIO_MODER_MODE10; /* clear mode for PA10 */
- GPIOA->MODER |= GPIO_MODER_MODE10_1; /* alt fn */
- GPIOA->OTYPER |= GPIO_OTYPER_OT_10; /* open drain */
- GPIOA->AFR[1] &= ~(15<<8); /* Clear Alternate Function PA10 */
- GPIOA->AFR[1] |= 1<<8; /* I2C Alternate Function PA10 */
-
-
- RCC->CCIPR &= ~RCC_CCIPR_I2C1SEL; /* write 00 to the I2C clk selection register */
- RCC->CCIPR |= RCC_CCIPR_I2C1SEL_0; /* select system clock (01) */
-
- /* I2C init flow chart: Clear PE bit */
-
- I2C1->CR1 &= ~I2C_CR1_PE;
-
- /* I2C init flow chart: Configure filter */
-
- /* leave at defaults */
- /* I2C init flow chart: Configure timing */
- /*
- standard mode 100kHz configuration
- SYSCLK = I2CCLK = 32 MHz
- PRESC = 6 bits 28..31
- SCLL = 0x13 bits 0..7
- SCLH = 0x0f bits 8..15
- SDADEL = 0x02 bits 16..19
- SCLDEL = 0x04 bits 20..23
- */
- I2C1->TIMINGR = 0x60420f13;
-
- /* I2C init flow chart: Configure NOSTRECH */
-
- I2C1->CR1 |= I2C_CR1_NOSTRETCH;
- /* I2C init flow chart: Enable I2C */
-
- I2C1->CR1 |= I2C_CR1_PE;
- /* disable OAR1 for reconfiguration */
- I2C1->OAR1 &= ~I2C_OAR1_OA1EN;
-
- I2C1->OAR1 = address;
-
- I2C1->OAR1 |= I2C_OAR1_OA1EN;
- /* enable interrupts */
- I2C1->CR1 |= I2C_CR1_STOPIE;
- I2C1->CR1 |= I2C_CR1_NACKIE;
- //I2C1->CR1 |= I2C_CR1_ADDRIE;
- I2C1->CR1 |= I2C_CR1_RXIE;
- I2C1->CR1 |= I2C_CR1_TXIE;
-
-
- /* load first value into TXDR register */
- I2C1->TXDR = i2c_mem[i2c_idx];
- /* enable IRQ in NVIC */
- NVIC_SetPriority(I2C1_IRQn, 0);
- NVIC_EnableIRQ(I2C1_IRQn);
-
- }
- void i2c_init(unsigned char address)
- {
- i2c_mem_init();
- i2c_hw_init(address);
- }
- void __attribute__ ((interrupt, used)) I2C1_IRQHandler(void)
- {
- unsigned long isr = I2C1->ISR;
- i2c_total_irq_cnt ++;
-
- if ( isr & I2C_ISR_TXIS )
- {
- i2c_TXIS_cnt++;
- I2C1->TXDR = i2c_mem_read();
- }
- else if ( isr & I2C_ISR_RXNE )
- {
- i2c_RXNE_cnt++;
- i2c_mem_write(I2C1->RXDR);
- I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
- I2C1->TXDR = i2c_mem[i2c_idx];
- }
- else if ( isr & I2C_ISR_STOPF )
- {
- I2C1->ICR = I2C_ICR_STOPCF;
- I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
- I2C1->TXDR = i2c_mem[i2c_idx];
- i2c_mem_reset_write();
- }
- else if ( isr & I2C_ISR_NACKF )
- {
- I2C1->ICR = I2C_ICR_NACKCF;
- I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
- I2C1->TXDR = i2c_mem[i2c_idx];
- i2c_mem_reset_write();
- }
- else if ( isr & I2C_ISR_ADDR )
- {
- /* not required, the addr match interrupt is not enabled */
- I2C1->ICR = I2C_ICR_ADDRCF;
- I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
- I2C1->TXDR = i2c_mem[i2c_idx];
- i2c_mem_reset_write();
- }
-
- /* if at any time the addr match is set, clear the flag */
- /* not sure, whether this is required */
- if ( isr & I2C_ISR_ADDR )
- {
- I2C1->ICR = I2C_ICR_ADDRCF;
- }
-
- }
- /*================================================*/
- volatile unsigned long SysTickCount = 0;
- void __attribute__ ((interrupt, used)) SysTick_Handler(void)
- {
- SysTickCount++;
- gpioNextState();
- }
- /*
- Delay by the provided number of system ticks.
- The delay must be smaller than the RELOAD value.
- This delay has an imprecision of about +/- 20 system ticks.
- */
- static void _delay_system_ticks_sub(uint32_t sys_ticks)
- {
- uint32_t start_val, end_val, curr_val;
- uint32_t load;
-
- start_val = SysTick->VAL;
- start_val &= 0x0ffffffUL;
- end_val = start_val;
-
- if ( end_val < sys_ticks )
- {
- /* check, if the operation after this if clause would lead to a negative result */
- /* if this would be the case, then add the reload value first */
- load = SysTick->LOAD;
- load &= 0x0ffffffUL;
- end_val += load;
- }
- /* counter goes towards zero, so end_val is below start value */
- end_val -= sys_ticks;
-
-
- /* wait until interval is left */
- if ( start_val >= end_val )
- {
- for(;;)
- {
- curr_val = SysTick->VAL;
- curr_val &= 0x0ffffffUL;
- if ( curr_val <= end_val )
- break;
- if ( curr_val > start_val )
- break;
- }
- }
- else
- {
- for(;;)
- {
- curr_val = SysTick->VAL;
- curr_val &= 0x0ffffffUL;
- if ( curr_val <= end_val && curr_val > start_val )
- break;
- }
- }
- }
- /*
- Delay by the provided number of system ticks.
- Any values between 0 and 0x0ffffffff are allowed.
- */
- void delay_system_ticks(uint32_t sys_ticks)
- {
- uint32_t load4;
- load4 = SysTick->LOAD;
- load4 &= 0x0ffffffUL;
- load4 >>= 2;
-
- while ( sys_ticks > load4 )
- {
- sys_ticks -= load4;
- _delay_system_ticks_sub(load4);
- }
- _delay_system_ticks_sub(sys_ticks);
- }
- void setHSIClock()
- {
-
-
- /* test if the current clock source is something else than HSI */
- if ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
- {
- /* enable HSI */
- RCC->CR |= RCC_CR_HSION;
- /* wait until HSI becomes ready */
- while ( (RCC->CR & RCC_CR_HSIRDY) == 0 )
- ;
-
- /* enable the HSI "divide by 4" bit */
- RCC->CR |= (uint32_t)(RCC_CR_HSIDIVEN);
- /* wait until the "divide by 4" flag is enabled */
- while((RCC->CR & RCC_CR_HSIDIVF) == 0)
- ;
-
-
- /* then use the HSI clock */
- RCC->CFGR = (RCC->CFGR & (uint32_t) (~RCC_CFGR_SW)) | RCC_CFGR_SW_HSI;
-
- /* wait until HSI clock is used */
- while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
- ;
- }
-
- /* disable PLL */
- RCC->CR &= (uint32_t)(~RCC_CR_PLLON);
- /* wait until PLL is inactive */
- while((RCC->CR & RCC_CR_PLLRDY) != 0)
- ;
- /* set latency to 1 wait state */
- FLASH->ACR |= FLASH_ACR_LATENCY;
-
- /* At this point the HSI runs with 4 MHz */
- /* Multiply by 16 device by 2 --> 32 MHz */
- RCC->CFGR = (RCC->CFGR & (~(RCC_CFGR_PLLMUL| RCC_CFGR_PLLDIV ))) | (RCC_CFGR_PLLMUL16 | RCC_CFGR_PLLDIV2);
-
- /* enable PLL */
- RCC->CR |= RCC_CR_PLLON;
-
- /* wait until the PLL is ready */
- while ((RCC->CR & RCC_CR_PLLRDY) == 0)
- ;
- /* use the PLL has clock source */
- RCC->CFGR |= (uint32_t) (RCC_CFGR_SW_PLL);
- /* wait until the PLL source is active */
- while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
- ;
- }
- void initGPIO(void)
- {
- RCC->IOPENR |= RCC_IOPENR_IOPAEN; /* Enable clock for GPIO Port A */
- __NOP();
- __NOP();
-
- GPIOA->MODER &= ~GPIO_MODER_MODE14; /* clear mode */
- GPIOA->MODER |= GPIO_MODER_MODE14_0; /* Output mode */
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_14; /* no Push/Pull */
- GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED14; /* low speed */
- GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD14; /* no pullup/pulldown */
- GPIOA->BSRR = GPIO_BSRR_BR_14; /* atomic clr */
-
- GPIOA->MODER &= ~GPIO_MODER_MODE13; /* clear mode */
- GPIOA->MODER |= GPIO_MODER_MODE13_0; /* Output mode */
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_13; /* no Push/Pull */
- GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED13; /* low speed */
- GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD13; /* no pullup/pulldown */
- GPIOA->BSRR = GPIO_BSRR_BR_13; /* atomic clr */
-
- GPIOA->MODER &= ~GPIO_MODER_MODE7; /* clear mode */
- GPIOA->MODER |= GPIO_MODER_MODE7_0; /* Output mode */
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_7; /* no Push/Pull */
- GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED7; /* low speed */
- GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD7; /* no pullup/pulldown */
- GPIOA->BSRR = GPIO_BSRR_BR_7; /* atomic clr */
- GPIOA->MODER &= ~GPIO_MODER_MODE6; /* clear mode */
- GPIOA->MODER |= GPIO_MODER_MODE6_0; /* Output mode */
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_6; /* no Push/Pull */
- GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED6; /* low speed */
- GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD6; /* no pullup/pulldown */
- GPIOA->BSRR = GPIO_BSRR_BR_6; /* atomic clr */
- GPIOA->MODER &= ~GPIO_MODER_MODE5; /* clear mode */
- GPIOA->MODER |= GPIO_MODER_MODE5_0; /* Output mode */
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_5; /* no Push/Pull */
- GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED5; /* low speed */
- GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD5; /* no pullup/pulldown */
- GPIOA->BSRR = GPIO_BSRR_BR_5; /* atomic clr */
- GPIOA->MODER &= ~GPIO_MODER_MODE4; /* clear mode */
- GPIOA->MODER |= GPIO_MODER_MODE4_0; /* Output mode */
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_4; /* no Push/Pull */
- GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED4; /* low speed */
- GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD4; /* no pullup/pulldown */
- GPIOA->BSRR = GPIO_BSRR_BR_4; /* atomic clr */
- GPIOA->MODER &= ~GPIO_MODER_MODE1; /* clear mode */
- GPIOA->MODER |= GPIO_MODER_MODE1_0; /* Output mode */
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_1; /* no Push/Pull */
- GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED1; /* low speed */
- GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD1; /* no pullup/pulldown */
- GPIOA->BSRR = GPIO_BSRR_BR_1; /* atomic clr */
- GPIOA->MODER &= ~GPIO_MODER_MODE0; /* clear mode */
- GPIOA->MODER |= GPIO_MODER_MODE0_0; /* Output mode */
- GPIOA->OTYPER &= ~GPIO_OTYPER_OT_0; /* no Push/Pull */
- GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED0; /* low speed */
- GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD0; /* no pullup/pulldown */
- GPIOA->BSRR = GPIO_BSRR_BR_0; /* atomic clr */
- }
- void clearGPIO(void)
- {
- GPIOA->BSRR = GPIO_BSRR_BR_14
- | GPIO_BSRR_BR_13
- | GPIO_BSRR_BR_7
- | GPIO_BSRR_BR_6
- | GPIO_BSRR_BR_5
- | GPIO_BSRR_BR_4
- | GPIO_BSRR_BR_1
- | GPIO_BSRR_BR_0;
- }
- /*
- 0: PA14
- 1: PA13
- 2: PA7
- 3: PA6
- 4: PA5
- 5: PA4
- 6: PA1
- 7: PA0
- */
- void setGPIO( uint8_t n )
- {
- clearGPIO();
- switch(n)
- {
- case 0: GPIOA->BSRR = GPIO_BSRR_BS_14; break;
- case 1: GPIOA->BSRR = GPIO_BSRR_BS_13; break;
- case 2: GPIOA->BSRR = GPIO_BSRR_BS_7; break;
- case 3: GPIOA->BSRR = GPIO_BSRR_BS_6; break;
- case 4: GPIOA->BSRR = GPIO_BSRR_BS_5; break;
- case 5: GPIOA->BSRR = GPIO_BSRR_BS_4; break;
- case 6: GPIOA->BSRR = GPIO_BSRR_BS_1; break;
- case 7: GPIOA->BSRR = GPIO_BSRR_BS_0; break;
- }
- }
- void setAllGPIO(void)
- {
- GPIOA->BSRR = GPIO_BSRR_BS_14
- | GPIO_BSRR_BS_13
- | GPIO_BSRR_BS_7
- | GPIO_BSRR_BS_6
- | GPIO_BSRR_BS_5
- | GPIO_BSRR_BS_4
- | GPIO_BSRR_BS_1
- | GPIO_BSRR_BS_0;
- }
- int main()
- {
- uint8_t i;
- initGPIO();
-
- setHSIClock();
- i2c_init(2*17);
-
- SysTick->LOAD = 32000*100 - 1; // 100 ms
- SysTick->VAL = 0;
- SysTick->CTRL = 7; /* enable, generate interrupt (SysTick_Handler), do not divide by 2 */
-
- /*
- for(;;)
- {
- delay_system_ticks(32000*200);
- setGPIO(7);
- delay_system_ticks(32000*200);
- clearGPIO();
- }
- */
-
- for( i = 0; i < 8; i++ )
- addCmdToGPIOQueue(i);
- for(;;)
- {
- processQueue();
- }
-
- }
|