diff --git a/CMakeLists.txt b/CMakeLists.txt index dfd11baca973536f6d83df0f6e0c5afede5e1639..3fa58b7393c826c0c00246d49efbc5ad066061a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(app PRIVATE ${KESTREL_SOURCE_DIR}/src/flash_filesystem.c ${KESTREL_SOURCE_DIR}/src/fsi.c ${KESTREL_SOURCE_DIR}/src/kestrel.c + ${KESTREL_SOURCE_DIR}/src/simple_pwm.c ${KESTREL_SOURCE_DIR}/src/webservice.c ${KESTREL_SOURCE_DIR}/src/webportal.c ${KESTREL_SOURCE_DIR}/src/direct_uart.c @@ -60,4 +61,4 @@ add_custom_target( COMMAND COMMAND ${CMAKE_COMMAND} -D KESTREL_SOURCE_DIR="${KESTREL_SOURCE_DIR}" -D embedded_file_sources="${embedded_file_sources_list}" -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_static_files.cmake DEPENDS ${embedded_file_sources} COMMENT "Generating C header file from static files" - ) \ No newline at end of file + ) diff --git a/kestrel/src/kestrel.c b/kestrel/src/kestrel.c index c93e5f97aa3670264f6525744d75e38ddcac4243..c25afbf4d6b32d2471fe959009e855f02e1f67f7 100644 --- a/kestrel/src/kestrel.c +++ b/kestrel/src/kestrel.c @@ -32,6 +32,7 @@ LOG_MODULE_REGISTER(kestrel_core, LOG_LEVEL_DBG); #include "aquila.h" #include "ipmi_bt.h" #include "opencores_i2c.h" +#include "simple_pwm.h" #include "kestrel.h" @@ -3455,6 +3456,10 @@ int kestrel_init(void) // initialize_i2c_master((uint8_t*)I2CMASTER3_BASE, 100000); initialize_i2c_master((uint8_t *)I2CMASTER4_BASE, 100000); +#ifdef SIMPLEPWM_BASE + initialize_pwm_controller(SIMPLEPWM_BASE); +#endif + // Check for Aquila core presence if ((read_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_DEVICE_ID_HIGH) == AQUILA_LPC_DEVICE_ID_HIGH) && (read_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_DEVICE_ID_LOW) == AQUILA_LPC_DEVICE_ID_LOW)) diff --git a/kestrel/src/simple_pwm.c b/kestrel/src/simple_pwm.c new file mode 100644 index 0000000000000000000000000000000000000000..761cbe19b71884d565ad2c6ecfed967aed98c356 --- /dev/null +++ b/kestrel/src/simple_pwm.c @@ -0,0 +1,86 @@ +// © 2020 - 2021 Raptor Engineering, LLC +// +// Released under the terms of the GPL v3 +// See the LICENSE file for full details + +#include <logging/log.h> +LOG_MODULE_REGISTER(kestrel_pwm, LOG_LEVEL_DBG); + +#include "simple_pwm.h" + +#include "utility.h" + +#include <generated/csr.h> +#include <generated/soc.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#define KESTREL_LOG(...) LOG_INF(__VA_ARGS__) + +int initialize_pwm_controller(uint8_t *base_address) +{ + KESTREL_LOG("Configuring PWM controller at address %p...", base_address); + + if ((*((volatile uint32_t *)(base_address + SIMPLE_PWM_MASTER_DEVICE_ID_HIGH)) != SIMPLE_PWM_DEVICE_ID_HIGH) || + (*((volatile uint32_t *)(base_address + SIMPLE_PWM_MASTER_DEVICE_ID_LOW)) != SIMPLE_PWM_DEVICE_ID_LOW)) + { + return -1; + } + uint32_t opencores_spi_version = *((volatile uint32_t *)(base_address + SIMPLE_PWM_MASTER_DEVICE_VERSION)); + KESTREL_LOG("OpenCores I2C master found, device version %0d.%0d.%d", + (opencores_spi_version >> SIMPLE_PWM_VERSION_MAJOR_SHIFT) & SIMPLE_PWM_VERSION_MAJOR_MASK, + (opencores_spi_version >> SIMPLE_PWM_VERSION_MINOR_SHIFT) & SIMPLE_PWM_VERSION_MINOR_MASK, + (opencores_spi_version >> SIMPLE_PWM_VERSION_PATCH_SHIFT) & SIMPLE_PWM_VERSION_PATCH_MASK); + { + KESTREL_LOG("Disabling PWM outputs"); + + set_pwm_value(base_address, 0, 0x00); + set_pwm_value(base_address, 1, 0x00); + set_pwm_value(base_address, 2, 0x00); + set_pwm_value(base_address, 3, 0x00); + + return 0; + } + + return 1; +} + +int set_pwm_value(uint8_t *base_address, uint8_t channel, uint8_t value) +{ + uint32_t dword; + + dword = *((volatile uint32_t *)(base_address + SIMPLE_PWM_MASTER_PWM_CTL)); + dword &= ~(0xff << (channel * 8)); + dword |= (value & 0xff) << (channel * 8); + *((volatile uint32_t *)(base_address + SIMPLE_PWM_MASTER_PWM_CTL)) = dword; + + return 0; +} + +uint8_t get_pwm_value(uint8_t *base_address, uint8_t channel) +{ + return (*((volatile uint32_t *)(base_address + SIMPLE_PWM_MASTER_PWM_CTL)) >> (channel * 8)) & 0xff; +} + +int get_tach_value(uint8_t *base_address, uint8_t channel) +{ + uint16_t raw_tach_value = 0; + int rps = 0; + int rpm = 0; + + if ((channel == 0) || (channel == 1)) + { + raw_tach_value = (*((volatile uint32_t *)(base_address + SIMPLE_PWM_MASTER_TACH_01)) >> ((channel & 0x1) * 16)) & 0xffff; + } + else if ((channel == 2) || (channel == 3)) + { + raw_tach_value = (*((volatile uint32_t *)(base_address + SIMPLE_PWM_MASTER_TACH_23)) >> ((channel & 0x1) * 16)) & 0xffff; + } + + // Compute RPM + rps = raw_tach_value * SIMPLE_PWM_TACH_SAMPLE_RATE_HZ; + rpm = rps * 60; + + return rpm; +} diff --git a/kestrel/src/simple_pwm.h b/kestrel/src/simple_pwm.h new file mode 100644 index 0000000000000000000000000000000000000000..156d5dcb904035350cf921406c829f92bf437f09 --- /dev/null +++ b/kestrel/src/simple_pwm.h @@ -0,0 +1,53 @@ +// © 2020 - 2021 Raptor Engineering, LLC +// +// Released under the terms of the GPL v3 +// See the LICENSE file for full details + +#ifndef _SIMPLE_PWM_H +#define _SIMPLE_PWM_H + +#include <stdint.h> + +#define SIMPLE_PWM_MASTER_DEVICE_ID_LOW 0x0 +#define SIMPLE_PWM_MASTER_DEVICE_ID_HIGH 0x4 +#define SIMPLE_PWM_MASTER_DEVICE_VERSION 0x8 +#define SIMPLE_PWM_MASTER_PWM_CTL 0xc +#define SIMPLE_PWM_MASTER_TACH_01 0x10 +#define SIMPLE_PWM_MASTER_TACH_23 0x14 + +#define SIMPLE_PWM_DEVICE_ID_HIGH 0x4932434d +#define SIMPLE_PWM_DEVICE_ID_LOW 0x4f50574d + +#define SIMPLE_PWM_VERSION_MAJOR_MASK 0xffff +#define SIMPLE_PWM_VERSION_MAJOR_SHIFT 16 +#define SIMPLE_PWM_VERSION_MINOR_MASK 0xff +#define SIMPLE_PWM_VERSION_MINOR_SHIFT 8 +#define SIMPLE_PWM_VERSION_PATCH_MASK 0xff +#define SIMPLE_PWM_VERSION_PATCH_SHIFT 0 + +#define SIMPLE_PWM_MASTER_PWM_0_MASK 0xff +#define SIMPLE_PWM_MASTER_PWM_0_SHIFT 0 +#define SIMPLE_PWM_MASTER_PWM_1_MASK 0xff +#define SIMPLE_PWM_MASTER_PWM_1_SHIFT 8 +#define SIMPLE_PWM_MASTER_PWM_2_MASK 0xff +#define SIMPLE_PWM_MASTER_PWM_2_SHIFT 16 +#define SIMPLE_PWM_MASTER_PWM_3_MASK 0xff +#define SIMPLE_PWM_MASTER_PWM_3_SHIFT 24 +#define SIMPLE_PWM_MASTER_TACH_0_MASK 0xffff +#define SIMPLE_PWM_MASTER_TACH_0_SHIFT 0 +#define SIMPLE_PWM_MASTER_TACH_1_MASK 0xffff +#define SIMPLE_PWM_MASTER_TACH_1_SHIFT 16 +#define SIMPLE_PWM_MASTER_TACH_2_MASK 0xffff +#define SIMPLE_PWM_MASTER_TACH_2_SHIFT 0 +#define SIMPLE_PWM_MASTER_TACH_3_MASK 0xffff +#define SIMPLE_PWM_MASTER_TACH_3_SHIFT 16 + +// This is currently hard-wired into the HDL to save die area +#define SIMPLE_PWM_TACH_SAMPLE_RATE_HZ 5 + +int initialize_pwm_controller(uint8_t *base_address); +int set_pwm_value(uint8_t *base_address, uint8_t channel, uint8_t value); +uint8_t get_pwm_value(uint8_t *base_address, uint8_t channel); +int get_tach_value(uint8_t *base_address, uint8_t channel); + +#endif // _SIMPLE_PWM_H