182 lines
4.5 KiB
C
182 lines
4.5 KiB
C
/* Reflow Oven Controller
|
|
*
|
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
|
*
|
|
* This file is part of the Reflow Oven Controller Project.
|
|
*
|
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* The Reflow Oven Control Firmware is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with the reflow oven controller project.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stm-periph/rcc-manager.h>
|
|
#include <helper-macros/helper-macros.h>
|
|
#include <stdlib.h>
|
|
#include <stm32/stm32f4xx.h>
|
|
|
|
struct rcc_enable_count {
|
|
volatile uint32_t *rcc_reg_addr;
|
|
uint32_t enable_bit_cnt;
|
|
uint8_t rcc_enable_bit_pos;
|
|
};
|
|
|
|
#if RCC_ENABLE_MANAGER_STATIC
|
|
|
|
static struct rcc_enable_count enable_count_list[RCC_ENABLE_MANAGER_COUNT] = {0};
|
|
|
|
#else
|
|
#error "RCC manager with dynamic memory not implemented!"
|
|
#endif
|
|
|
|
#if RCC_ENABLE_MANAGER_STATIC
|
|
static struct rcc_enable_count *search_enable_entry_in_list(volatile uint32_t *reg_addr, uint8_t bit_pos)
|
|
{
|
|
unsigned int i;
|
|
struct rcc_enable_count *ret_element = NULL;
|
|
struct rcc_enable_count *current_element;
|
|
|
|
for (i = 0; i < COUNT_OF(enable_count_list); i++) {
|
|
current_element = &enable_count_list[i];
|
|
|
|
/* Check if register address and bit position match */
|
|
if (reg_addr != current_element->rcc_reg_addr)
|
|
continue;
|
|
if (bit_pos != current_element->rcc_enable_bit_pos)
|
|
continue;
|
|
|
|
/* Found entry. Wohoo! */
|
|
ret_element = current_element;
|
|
}
|
|
|
|
return ret_element;
|
|
}
|
|
|
|
static struct rcc_enable_count *enable_entry_list_get_free_entry()
|
|
{
|
|
struct rcc_enable_count *ret_ptr = NULL;
|
|
const int list_len = COUNT_OF(enable_count_list);
|
|
int i;
|
|
|
|
for (i = 0; i < list_len; i++) {
|
|
if (enable_count_list[i].rcc_reg_addr == NULL) {
|
|
ret_ptr = &enable_count_list[i];
|
|
|
|
/* Clear the count value to be safe */
|
|
ret_ptr->enable_bit_cnt = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret_ptr;
|
|
}
|
|
|
|
static void enable_entry_list_remove_entry(struct rcc_enable_count *entry)
|
|
{
|
|
if (!entry)
|
|
return;
|
|
|
|
entry->rcc_reg_addr = NULL;
|
|
entry->enable_bit_cnt = 0;
|
|
entry->rcc_enable_bit_pos = 0;
|
|
}
|
|
#endif
|
|
|
|
int rcc_manager_enable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no)
|
|
{
|
|
int ret_val = 0;
|
|
struct rcc_enable_count *entry;
|
|
|
|
if (!rcc_enable_register || bit_no > 31)
|
|
return -1000;
|
|
|
|
/* Enable the clock in any case, no matter what follows */
|
|
*rcc_enable_register |= (1U<<bit_no);
|
|
|
|
/* Check if bit is already in list */
|
|
entry = search_enable_entry_in_list(rcc_enable_register, bit_no);
|
|
|
|
if (!entry) {
|
|
/* Create ne entry at first free place in list */
|
|
entry = enable_entry_list_get_free_entry();
|
|
|
|
/* Check if entry is valid. If not return */
|
|
if (!entry) {
|
|
ret_val = -1;
|
|
goto ret_error_code;
|
|
}
|
|
|
|
/* Set entry */
|
|
entry->rcc_reg_addr = rcc_enable_register;
|
|
entry->rcc_enable_bit_pos = bit_no;
|
|
}
|
|
|
|
/* Increment enable counter */
|
|
entry->enable_bit_cnt++;
|
|
|
|
ret_error_code:
|
|
return ret_val;
|
|
}
|
|
|
|
int rcc_manager_disable_clock(volatile uint32_t *rcc_enable_register, uint8_t bit_no)
|
|
{
|
|
int ret_val = -1;
|
|
struct rcc_enable_count *entry;
|
|
|
|
if (!rcc_enable_register || bit_no > 31)
|
|
return -1000;
|
|
|
|
entry = search_enable_entry_in_list(rcc_enable_register, bit_no);
|
|
|
|
/* If entry is found and has a count of zero, disable clock */
|
|
if (entry) {
|
|
/* Found entry => Decrement count and delete if zero */
|
|
entry->enable_bit_cnt--;
|
|
if (entry->enable_bit_cnt <= 0) {
|
|
enable_entry_list_remove_entry(entry);
|
|
|
|
/* Disable clock */
|
|
*rcc_enable_register &= ~(1U<<bit_no);
|
|
}
|
|
|
|
ret_val = 0;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
enum rcc_reset_source rcc_manager_get_reset_cause(bool clear_flags)
|
|
{
|
|
enum rcc_reset_source ret = 0;
|
|
uint32_t rcc_csr;
|
|
|
|
rcc_csr = RCC->CSR;
|
|
if (rcc_csr & RCC_CSR_LPWRRSTF)
|
|
ret |= RCC_RESET_SOURCE_LOW_POWER;
|
|
if (rcc_csr & RCC_CSR_WWDGRSTF)
|
|
ret |= RCC_RESET_SOURCE_WWD;
|
|
if (rcc_csr & RCC_CSR_WDGRSTF)
|
|
ret |= RCC_RESET_SOURCE_IWDG;
|
|
if (rcc_csr & RCC_CSR_SFTRSTF)
|
|
ret |= RCC_RESET_SOURCE_SOFTWARE;
|
|
if (rcc_csr & RCC_CSR_PORRSTF)
|
|
ret |= RCC_RESET_SOURCE_POWER_ON;
|
|
if (rcc_csr & RCC_CSR_PADRSTF)
|
|
ret |= RCC_RESET_SOURCE_PIN;
|
|
if (rcc_csr & RCC_CSR_BORRSTF)
|
|
ret |= RCC_RESET_BOR_POR;
|
|
|
|
if (clear_flags)
|
|
RCC->CSR |= RCC_CSR_RMVF;
|
|
|
|
return ret;
|
|
}
|