Skip to content

Instantly share code, notes, and snippets.

@dgrubb
Last active October 6, 2020 09:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dgrubb/101a25f508e43b950ed45fa979d19397 to your computer and use it in GitHub Desktop.
Save dgrubb/101a25f508e43b950ed45fa979d19397 to your computer and use it in GitHub Desktop.
HiFive1 PWM interrupt sample
/* 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;
}
@gigalinkhw
Copy link

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment