Last active
October 6, 2020 09:23
-
-
Save dgrubb/101a25f508e43b950ed45fa979d19397 to your computer and use it in GitHub Desktop.
HiFive1 PWM interrupt sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* HiFive1/FE310 includes */ | |
#include "platform.h" | |
#include "encoding.h" | |
#include "plic/plic_driver.h" | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <unistd.h> | |
#define PWM_SCALE 0x1 | |
#define PWM_FREQ 100 | |
#define PWM_DUTY PWM_FREQ/2 // 50% duty cycle | |
// Instance data for the PLIC. | |
static plic_instance_t g_plic; | |
volatile int invert_LEDs = 0; | |
void handle_m_time_interrupt() | |
{ | |
} | |
void handle_m_ext_interrupt() | |
{ | |
plic_source int_num = PLIC_claim_interrupt(&g_plic); | |
switch (int_num) { | |
case 0: | |
break; | |
case INT_PWM1_BASE: | |
PWM1_REG(PWM_CFG) &= ~PWM_CFG_CMP0IP; | |
invert_LEDs = 1; | |
break; | |
} | |
PLIC_complete_interrupt(&g_plic, int_num); | |
} | |
void init_PWM() | |
{ | |
PLIC_init(&g_plic, PLIC_CTRL_ADDR, PLIC_NUM_INTERRUPTS, PLIC_NUM_PRIORITIES); | |
PLIC_enable_interrupt(&g_plic, INT_PWM1_BASE); | |
PLIC_set_threshold(&g_plic, 0); | |
PLIC_set_priority(&g_plic, INT_PWM1_BASE, 1); | |
/* Configure PWM */ | |
PWM1_REG(PWM_CFG) = 0; // Clear the configuration register | |
/* This is the real meat of things. PWM configuration register bits are | |
* documented in the SiFive E300 Platform Reference Manual: | |
* | |
* https://www.sifive.com/documentation/freedom-soc/freedom-e300-platform-reference-manual/ | |
*/ | |
PWM1_REG(PWM_CFG) = | |
(PWM_CFG_ENALWAYS) | | |
(PWM_CFG_ZEROCMP) | | |
(PWM_CFG_STICKY) | | |
(PWM_SCALE); | |
PWM1_REG(PWM_CMP0) = PWM_FREQ; | |
PWM1_REG(PWM_CMP1) = PWM_DUTY; | |
PWM1_REG(PWM_CMP2) = PWM_DUTY; | |
PWM1_REG(PWM_CMP3) = PWM_DUTY; | |
PWM1_REG(PWM_COUNT) = 0; | |
/* Re-enable timers */ | |
set_csr(mie, MIP_MTIP); | |
set_csr(mstatus, MSTATUS_MIE); | |
} | |
void init_GPIO() | |
{ | |
GPIO_REG(GPIO_OUTPUT_EN) |= (1 << GREEN_LED_OFFSET); | |
GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << GREEN_LED_OFFSET); | |
} | |
int main() | |
{ | |
init_GPIO(); | |
init_PWM(); | |
puts("PWM setup complete, periodically inverting the green LED ..."); | |
while (1) { | |
if (invert_LEDs) { | |
GPIO_REG(GPIO_OUTPUT_VAL) ^= (0x1 << GREEN_LED_OFFSET); | |
invert_LEDs = 0; | |
} | |
}; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi sir, first I'll thank you for this example, however, I tried this on Arty and the LED won't blink. I've also noticed that you said you've done the PWM external facing signal lab in this post "https://forums.sifive.com/t/pwm-interrupts-or-how-i-learned-to-stop-worrying-and-love-the-plic/813" , does that mean you assigned PWM signal to GPIO? If it was, would you mind teaching me how to complete this assignment?