Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * PIC12F1822 I2C SLAVE PWM - PWM(P1A/TMR2), I2C Slave, WDT
- * File: main.c
- * Author: munjeni (http://github.com/munjeni)
- * Date 31.May.2020.
- *
- * PIC12F1822-I/P
- * -------------------
- * | |
- * [VDD] |1 8| [VSS]
- * | |
- * PWM <--- P1A [RA5] |2 7| [RA0/ICSPDAT]
- * | |
- * ---> AN3 [RA4] |3 6| [RA1/ICSPCLK] <--- SCL
- * | |
- * [MCLR/VPP/RA3] |4 5| [RA2] <--> SDA
- * | |
- * -------------------
- *
- */
- // CONFIG1
- #pragma config FOSC = INTOSC // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
- #pragma config WDTE = OFF // Watchdog Timer Enable->WDT disabled
- #pragma config PWRTE = OFF // Power-up Timer Enable->PWRT disabled
- #pragma config MCLRE = OFF // MCLR Pin Function Select->MCLR/VPP pin function is digital input
- #pragma config CP = ON // Flash Program Memory Code Protection->Program memory code protection is enabled
- #pragma config CPD = ON // Data Memory Code Protection->Data memory code protection is enabled
- #pragma config BOREN = ON // Brown-out Reset Enable->Brown-out Reset enabled
- #pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
- #pragma config IESO = ON // Internal/External Switchover->Internal/External Switchover mode is enabled
- #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled
- // CONFIG2
- #pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off
- #pragma config PLLEN = OFF // PLL Enable->4x PLL disabled
- #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
- #pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
- #pragma config LVP = OFF // Low-Voltage Programming Enable->High-voltage on MCLR/VPP must be used for programming
- #include <xc.h>
- #define _XTAL_FREQ 32000000
- #include <stdint.h>
- #include <stdbool.h>
- // write default values to eeprom during programming
- __EEPROM_DATA(0xee, 0xff, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00); // enabled, PR2, CCPR1L
- #define I2C_SLAVE_ADDRESS 0x2a
- #define I2C_SLAVE_MASK 0xff
- #define I2C_BUFFERSIZE 16
- #define SSPBUFIDX_SLEEP 0
- #define SSPBUFIDX_PR2 1
- #define SSPBUFIDX_CCPR1L 2
- #define SSPBUFIDX_SAVE 3
- #define SSPBUFIDX_MAX 4
- static const uint8_t ENABLED = 0xee;
- static const uint8_t DISABLED = 0xdd;
- static inline void I2C_SlaveReleaseClock(void)
- {
- SSP1CON1bits.CKP = 1;
- }
- #if 0
- static inline bool I2C_SlaveIsData()
- {
- return SSP1STATbits.D_nA;
- }
- static inline bool I2C_SlaveIsAddr(void)
- {
- return !(SSP1STATbits.D_nA);
- }
- static inline bool I2C_SlaveIsRead(void)
- {
- return (SSP1STATbits.R_nW);
- }
- static inline bool I2C_SlaveIsWrite(void)
- {
- return !(SSP1STATbits.R_nW);
- }
- #endif
- static inline bool I2C_SlaveIsNACK(void)
- {
- return SSP1CON2bits.ACKSTAT;
- }
- static inline void mssp_clearIRQ(void)
- {
- PIR1bits.SSP1IF = 0;
- }
- static inline void SYS_IO_init(void)
- {
- nWPUEN = 0; // Enable all weak pull-up resistors
- ANSELA = 0; // Disable all analog functions first
- #if 0
- ANSA4 = 1; // Enable analog on RA4
- #endif
- // Configure RA5 pin as a digital output for CCP1/P1A
- TRISA5 = 0;
- // Alternate Pin Config: Route CCP1/P1A function to RA5 (PIC12(L)F1822 only)
- CCP1SEL = 1;
- // Configure RA1 as digital in (SCL), disable analog, enable weak pull-up
- TRISA1 = 1;
- ANSA1 = 0;
- WPUA1 = 1;
- // Configure RA2 as digital in (SDA), disable analog, enable weak pull-up
- TRISA2 = 1;
- ANSA2 = 0;
- WPUA2 = 1;
- }
- static inline void OSCILLATOR_Initialize(void)
- {
- // SPLLEN enabled; IRCF 32MHz_HF; SCS Clock determined by FOSC<2:0> in Configuration Word 1;
- OSCCON = 0b11110000;
- // TUN 0;
- OSCTUNE = 0x00;
- // SBOREN disabled;
- BORCON = 0x00;
- }
- static inline void PIC12_TMR2_init(void)
- {
- T2CONbits.T2CKPS = 1; // Timer prescale value = 4
- // Calculate what PR2 should be to achieve 6kHz
- // Period = {[PR2 + 1] * 4 * Tosc * T2CKPS}
- // (1/6000) = {[PR2 + 1] * 4 * (1 / 8 MHz) * 4}
- PR2 = 0xff;
- TMR2ON = 1; // Enable Timer2
- }
- #define CCP1_OFF 0
- #define PWM_P1AP1C_AH 12
- static inline void PIC12_ECCP_init(void)
- {
- CCP1CONbits.P1M = 0; // Single Output; P1A modulated
- CCP1CONbits.DC1B = 0x03; // The two LSB's of the 10-bit duty cycle
- CCP1CONbits.CCP1M = PWM_P1AP1C_AH; // PWM mode: P1A,P1C active high
- CCPR1L = (PR2 >> 1); // PWM duty cycle = 50%
- }
- static inline void PIC12_I2C_Slave_init(void)
- {
- // SMP Slew rate control disbled; CKE enabled;
- SSP1STAT = 0xc0;
- // SSPEN enabled; CKP enabled; SSPM 7-bit address;
- SSP1CON1 = 0x36;
- // ACKEN disabled; GCEN disabled; PEN disabled; ACKDT acknowledge; RSEN disabled; RCEN disabled; SEN disabled;
- SSP1CON2 = 0x00;
- // SBCDE enabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled;
- SSP1CON3 = 0x04;
- // SSPMSK;
- SSP1MSK = I2C_SLAVE_MASK;
- // SSPADD;
- SSP1ADD = (I2C_SLAVE_ADDRESS << 1);
- PIR2bits.BCL1IF = 0; // Clear Bus Collision flag
- PIR1bits.SSP1IF = 0; // Clear SSP interrupt flag
- PIE2bits.BCL1IE = 1; // Enable Bus Collision interrupt
- PIE1bits.SSP1IE = 1; // Enable SSP interrupt
- }
- #define GlobalInterruptEnable() (INTCONbits.GIE = 1)
- #define PeripheralInterruptEnable() (INTCONbits.PEIE = 1)
- #define MWA 0b00001001 // 0x09 master write last was address
- #define MWD 0b00101001 // 0x29 master write last was data
- #define MRA 0b00001101 // 0x0d master read last was address
- #define MRD 0b00101100 // 0x2c master read last was data
- #define END 0b00101000 // 0x28 master nack
- static uint8_t SSP_bufIndex = 0;
- static uint8_t SSPBuffer[I2C_BUFFERSIZE];
- static uint8_t BUF_temp;
- static uint8_t i2cStatus;
- static uint8_t registerIndex = 0;
- void __interrupt() ISR(void)
- {
- if (PIR1bits.SSP1IF)
- {
- i2cStatus = (SSP1STAT & 0b00101101); // Mask out unimportant bits
- switch (i2cStatus)
- {
- case MWA:
- BUF_temp = SSP1BUF; // Read out to clear BF
- SSP_bufIndex = 0; // Initialize index
- break;
- case MWD:
- BUF_temp = SSP1BUF; // Read out to clear BF
- switch (SSP_bufIndex)
- {
- case 0:
- registerIndex = BUF_temp;
- SSP_bufIndex = 1;
- break;
- case 1:
- if (registerIndex < (uint8_t)SSPBUFIDX_MAX)
- {
- SSPBuffer[registerIndex] = BUF_temp;
- }
- break;
- default:
- break;
- }
- break;
- case MRA:
- BUF_temp = SSP1BUF; // Read out to clear BF
- if (!I2C_SlaveIsNACK()) // Only if acknownledged.
- {
- if (registerIndex < (uint8_t)SSPBUFIDX_MAX)
- {
- SSP1BUF = SSPBuffer[registerIndex];
- registerIndex++;
- }
- else
- {
- SSP1BUF = 0x11; // write dummy data in case index is beyond buffer
- registerIndex = 0;
- }
- }
- break;
- case MRD:
- if (!I2C_SlaveIsNACK()) // Only if acknownledged.
- {
- if (registerIndex < (uint8_t)SSPBUFIDX_MAX)
- {
- SSP1BUF = SSPBuffer[registerIndex];
- registerIndex++;
- }
- else
- {
- SSP1BUF = 0x11; // write dummy data in case index is beyond buffer
- registerIndex = 0;
- }
- }
- break;
- case END:
- break;
- default:
- break;
- }
- I2C_SlaveReleaseClock(); // Ensure clock stretching released
- if (SSPBuffer[SSPBUFIDX_SLEEP] == ENABLED)
- {
- CCP1CONbits.CCP1M = PWM_P1AP1C_AH; // PWM mode: P1A,P1C active high
- }
- else
- {
- CCP1CONbits.CCP1M = CCP1_OFF; // Capture/Compare/PWM = OFF
- LATA5 = 0; // Force PWM output low
- }
- PR2 = SSPBuffer[SSPBUFIDX_PR2];
- CCPR1L = SSPBuffer[SSPBUFIDX_CCPR1L];
- if (SSPBuffer[SSPBUFIDX_SAVE] == 's') // s = save
- {
- eeprom_write(0, SSPBuffer[SSPBUFIDX_SLEEP]);
- eeprom_write(1, SSPBuffer[SSPBUFIDX_PR2]);
- eeprom_write(2, SSPBuffer[SSPBUFIDX_CCPR1L]);
- SSPBuffer[SSPBUFIDX_SAVE] = 'd'; // d = done
- }
- if (SSPBuffer[SSPBUFIDX_SLEEP] != ENABLED)
- {
- SLEEP();
- }
- mssp_clearIRQ(); // clear the interrupt flag
- }
- if (PIR2bits.BCL1IF)
- {
- BUF_temp = SSP1BUF; // Clear BF
- I2C_SlaveReleaseClock();
- PIR2bits.BCL1IF = 0;
- }
- }
- int main(void)
- {
- SYS_IO_init(); // Initialize I/O functions
- OSCILLATOR_Initialize(); // Initialize System Clock
- PIC12_TMR2_init(); // Initialize Timer2
- PIC12_ECCP_init(); // Initialize ECCP module
- PIC12_I2C_Slave_init(); // Initialize I2C Slave
- GlobalInterruptEnable(); // Enable Global interrupts
- PeripheralInterruptEnable(); // Enable Peripheral interrupts
- uint8_t status = eeprom_read(0);
- if (status == ENABLED || status == DISABLED)
- {
- if (status == ENABLED)
- SSPBuffer[SSPBUFIDX_SLEEP] = ENABLED;
- else
- SSPBuffer[SSPBUFIDX_SLEEP] = DISABLED;
- }
- else
- {
- SSPBuffer[SSPBUFIDX_SLEEP] = ENABLED;
- }
- SSPBuffer[SSPBUFIDX_PR2] = eeprom_read(1);
- SSPBuffer[SSPBUFIDX_CCPR1L] = eeprom_read(2);
- SSPBuffer[SSPBUFIDX_SAVE] = 'd';
- while(1)
- {
- // loop
- }
- }
Add Comment
Please, Sign In to add comment