Using internal oscillator to blink UBW lights

USB PICs and the UBW

Moderator: phalanx

Post Reply
Ultima
Posts: 12
Joined: Wed Dec 26, 2012 4:39 am

Using internal oscillator to blink UBW lights

Post by Ultima » Sat Jul 13, 2013 9:19 am

Hi,

I've been working on this for a few days now, but I'm slightly stuck. I'm trying to convert the HelloUsbWorld code to achieve my goal. In the function ProcessIO I have added some code which I think should prepare the TMR0. It then should enter an infinite loop where interrupts switch a led on and off. However, the UBW gets stuck in the setup code (the led goes off and on once).

The code I have in ProcessIO is:

Code: Select all

		mLED_2_Toggle();
		Delay10KTCYx (240);/*200ms*/
		Delay10KTCYx (240);
		Delay10KTCYx (240);
		Delay10KTCYx (240);
		Delay10KTCYx (240);


		mLED_2_Toggle();
		Delay10KTCYx (240);/*200ms*/
		Delay10KTCYx (240);
		Delay10KTCYx (240);
		Delay10KTCYx (240);
		Delay10KTCYx (240);

 	//TRISBbits.TRISB3 = 0;         //set portB pin 3 (red LED) to output 
	//T0CON = 0xC7;                     //turn on Timer0 and set prescaler to 1:256
	//INTCONbits.TMR0IE = 1; //enable the interrupt for Timer0 overflow
	//INTCONbits.GIE = 1; //global interrupt enable ON

    //TRISBbits.TRISB0 = 0;    // make led pin an output      
    T0CONbits.T08BIT = 0;    // use 16 bit timer (=1 implies 8 bit)
    T0CONbits.T0CS = 0;      // use instruction cycle clock
    T0CONbits.T0PS = 255;    // timer 0 prescaler
    T0CONbits.TMR0ON =1;     // timer 0 enable
    INTCONbits.GIE = 1;      // global interrupt enable
    INTCONbits.TMR0IF = 0;   // clear timer 0 interrupt flag
    INTCONbits.TMR0IE = 1;   // enable the timer 0 interrupt

		mLED_2_Toggle();
		Delay10KTCYx (240);/*200ms*/
		Delay10KTCYx (240);
		Delay10KTCYx (240);
		Delay10KTCYx (240);
		Delay10KTCYx (240);


		mLED_2_Toggle();
		Delay10KTCYx (240);/*200ms*/
		Delay10KTCYx (240);
		Delay10KTCYx (240);
		Delay10KTCYx (240);
		Delay10KTCYx (240);

		mLED_2_Toggle();

	while(1); //<-------Infinite loop


Probably not relevant yet, but the code I added in YourHighPriorityISRCode() is:

Code: Select all

		 if(INTCONbits.TMR0IF){
			//LATBbits.LATB3 ^= 1;       //Toggle portB pin 3 (red LED)
			mLED_2_Toggle();
			INTCONbits.TMR0IF = 0; //clear the interrupt flag so that another interrupt can happen
			
			TMR0L = 0x0;   //re-initialise timer0 
		}

Looking at some examples I'm finding it a bit difficult to distinguish which function calls are compatible with the UBW, so I am trying to stick with 18F examples as much as possible.

Cheers,
Ultima

bsagan
Posts: 39
Joined: Fri Jun 28, 2013 4:31 pm

Re: Using internal oscillator to blink UBW lights

Post by bsagan » Fri Jul 19, 2013 10:51 am

So I can't remember exactly which microcontroller I was working with when this was beat into my brain, but I distinctly remember there is a timer interrupt flag that HAS to be cleared by writing a 1 to that bit. Honestly can't remember if it was a PIC (don't think it was, think it was a Freescale mc) where this was necessary but that's my first thought.

There are also a couple different interrupt settings and I don't know which you have selected from the top of my head. For your application, you can have the interrupt trigger on a timer overflow or you can set up an output compare. You seem to be set up for a timer overflow situation but make sure you have the correct command register bits selected for this mode. Also you don't need to reset the timer in the interrupt function since it has overflowed. You'll actually get a slightly different period than you expect from the value you set in the timer since the timer will be running while you toggle the LED. Probably imperceptible in this case but if you had more complicated, time consuming math there, it would be noticeable.

Also would be helpful to see the whole function 'YourHighPriorityISRCode().' There is some specific syntax you need to create an interrupt but you should be fine there if you are using example code.

Lastly, is this the right forum for this question haha?

Ultima
Posts: 12
Joined: Wed Dec 26, 2012 4:39 am

Re: Using internal oscillator to blink UBW lights

Post by Ultima » Mon Jul 22, 2013 12:18 am

Hi Bsagen, thanks for taking the time to think over my problem, every little bit helps.

I am new to PIC programming and since the UBW has some customised attributes, I figured it was best to start here in case something I was doing was prevented by this. (This forum topic mentions UBW in its description).

I don't think the code gets a chance to execute the interrupt routine for the timer, even so I think I have included the reset part (INTCONbits.TMR0IF = 0) - later I will probably move the blink LED outside (thanks for this tip about accuracy).

The complete YourHighPriorityISRCode() is at the end of the appended code below.


I have about 20 places I have referenced for the code, but to give an idea of where I am coming from, a few principal ones are:
https://sites.google.com/a/midaslab.net ... interrupts
http://www.foxytronics.com/learn/microc ... le-program
http://blog.irwellsprings.com/getting-s ... nterrupts/
http://forum.allaboutcircuits.com/showt ... hp?t=53276
http://www.microchip.com/forums/m305248.aspx
http://www.8051projects.net/lofiversion ... rupts.html


Perhaps it might have something to do with initial configuration so I have appended this. But if I understand the code below correctly, the only relevant part is "elif defined(UBW)". I've pasted this below (sorry about the length, I have trimmed out the code from the elif I'm fairly sure have no effect):

/********************************************************************
FileName: main.c
Dependencies: See INCLUDES section
Processor: PIC18, PIC24, and PIC32 USB Microcontrollers
Hardware: This demo is natively intended to be used on Microchip USB demo
boards supported by the MCHPFSUSB stack. See release notes for
support matrix. This demo can be modified for use on other hardware
platforms.
Complier: Microchip C18 (for PIC18), C30 (for PIC24), C32 (for PIC32)
Company: Microchip Technology, Inc.

Software License Agreement:

The software supplied herewith by Microchip Technology Incorporated
(the “Company”) for its PIC® Microcontroller is intended and
supplied to you, the Company’s customer, for use solely and
exclusively on Microchip PIC Microcontroller products. The
software is owned by the Company and/or its supplier, and is
protected under applicable copyright laws. All rights are reserved.
Any use in violation of the foregoing restrictions may subject the
user to criminal sanctions under applicable laws, as well as to
civil liability for the breach of the terms and conditions of this
license.

THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.

********************************************************************
File Description:

Change History:
Rev Description
---- -----------------------------------------
1.0 Initial release
2.1 Updated for simplicity and to use common
coding style
2.6A Added button debouncing using Start-of-Frame packets
********************************************************************/

/** INCLUDES *******************************************************/
#include "./USB/usb.h"
#include "./USB/usb_function_cdc.h"

#include "HardwareProfile.h"

#include "delays.h"


/** CONFIGURATION **************************************************/
#if defined(PICDEM_FS_USB) // Configuration bits for PICDEM FS USB Demo Board (based on PIC18F4550)
#pragma config PLLDIV = 5 // (20 MHz crystal on PICDEM FS USB board)
#pragma config CPUDIV = OSC1_PLL2 //CRR Divide freq by 2 (PLL3, PLL4 and PLL6 also exist)
#pragma config USBDIV = 2 // Clock source from 96MHz PLL/2
#pragma config FOSC = HSPLL_HS
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = ON
#pragma config BORV = 3
#pragma config VREGEN = ON //USB Voltage Regulator
#pragma config WDT = OFF //(CRR) Watchdog timer?
#pragma config WDTPS = 32768
#pragma config MCLRE = ON
#pragma config LPT1OSC = OFF
#pragma config PBADEN = OFF
// #pragma config CCP2MX = ON
#pragma config STVREN = ON
#pragma config LVP = OFF
// #pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming
#pragma config XINST = OFF // Extended Instruction Set
#pragma config CP0 = OFF
#pragma config CP1 = OFF
// #pragma config CP2 = OFF
// #pragma config CP3 = OFF
#pragma config CPB = OFF
// #pragma config CPD = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
// #pragma config WRT2 = OFF
// #pragma config WRT3 = OFF
#pragma config WRTB = OFF // Boot Block Write Protection
#pragma config WRTC = OFF
// #pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
// #pragma config EBTR2 = OFF
// #pragma config EBTR3 = OFF
#pragma config EBTRB = OFF


#elif defined(PIC18F87J50_PIM) // Configuration bits for PIC18F87J50 FS USB Plug-In Module board
//I assume irrelevant code here.

#elif defined(PIC18F46J50_PIM) || defined(PIC18F_STARTER_KIT_1) || defined(PIC18F47J53_PIM)
#pragma config WDTEN = OFF //WDT disabled (enabled by SWDTEN bit)
#pragma config PLLDIV = 3 //Divide by 3 (12 MHz oscillator input)
#pragma config STVREN = ON //stack overflow/underflow reset enabled
#pragma config XINST = OFF //Extended instruction set disabled
#pragma config CPUDIV = OSC1 //No CPU system clock divide
#pragma config CP0 = OFF //Program memory is not code-protected
#pragma config OSC = HSPLL //HS oscillator, PLL enabled, HSPLL used by USB
//#pragma config T1DIG = ON //Sec Osc clock source may be selected
//#pragma config LPT1OSC = OFF //high power Timer1 mode
#pragma config FCMEN = OFF //Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF //Two-Speed Start-up disabled
#pragma config WDTPS = 32768 //1:32768
#pragma config DSWDTOSC = INTOSCREF //DSWDT uses INTOSC/INTRC as clock
#pragma config RTCOSC = T1OSCREF //RTCC uses T1OSC/T1CKI as clock
#pragma config DSBOREN = OFF //Zero-Power BOR disabled in Deep Sleep
#pragma config DSWDTEN = OFF //Disabled
#pragma config DSWDTPS = 8192 //1:8,192 (8.5 seconds)
#pragma config IOL1WAY = OFF //IOLOCK bit can be set and cleared
#pragma config MSSP7B_EN = MSK7 //7 Bit address masking
#pragma config WPFP = PAGE_1 //Write Protect Program Flash Page 0
#pragma config WPEND = PAGE_0 //Start protection at page 0
#pragma config WPCFG = OFF //Write/Erase last page protect Disabled
#pragma config WPDIS = OFF //WPFP[5:0], WPEND, and WPCFG bits ignored
#elif defined(LOW_PIN_COUNT_USB_DEVELOPMENT_KIT)
//14K50
#pragma config CPUDIV = NOCLKDIV
#pragma config USBDIV = OFF
#pragma config FOSC = HS
#pragma config PLLEN = ON
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRTEN = OFF
#pragma config BOREN = OFF
#pragma config BORV = 30
// #pragma config VREGEN = ON
#pragma config WDTEN = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = OFF
#pragma config HFOFST = OFF
#pragma config STVREN = ON
#pragma config LVP = OFF
#pragma config XINST = OFF
#pragma config BBSIZ = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CPB = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTRB = OFF

#elif defined(EXPLORER_16)
//I assume irrelevant code here.
#elif defined(__PIC24FJ64GB004__)
//I assume irrelevant code here.
#elif defined(__32MX460F512L__) || defined(__32MX795F512L__)
//I assume irrelevant code here.
#elif defined(PIC24F_STARTER_KIT)
//I assume irrelevant code here.
#elif defined(PIC24FJ256DA210_DEV_BOARD)
//I assume irrelevant code here.
#elif defined(PIC32_USB_STARTER_KIT)
//I assume irrelevant code here.
#elif defined(UBW)
// On purpose we don't include any config bit here, because the bootloader on the UBW
// already includes all necessary config bits set for us, and we don't want to mess that up.
#else
#error No hardware board defined, see "HardwareProfile.h" and __FILE__
#endif

/** I N C L U D E S **********************************************************/

#include "GenericTypeDefs.h"
#include "Compiler.h"
#include "usb_config.h"
#include "USB\usb_device.h"
#include "USB\usb.h"

#include "HardwareProfile.h"

//CRR addition -based on ref 2 <- though suggested that this may interfere with usb
#pragma config FOSC = HSPLL_HS // But I do need to start the oscillator...

/** V A R I A B L E S ********************************************************/
#pragma udata
char USB_In_Buffer[64];
char USB_Out_Buffer[64];

BOOL stringPrinted;
volatile BOOL buttonPressed;
volatile BYTE buttonCount;

/** P R I V A T E P R O T O T Y P E S ***************************************/
static void InitializeSystem(void);
void ProcessIO(void);
void USBDeviceTasks(void);
void YourHighPriorityISRCode();
void YourLowPriorityISRCode();
void BlinkUSBStatus(void);
void UserInit(void);

/** VECTOR REMAPPING ***********************************************/
#if defined(__18CXX)
//On PIC18 devices, addresses 0x00, 0x08, and 0x18 are used for
//the reset, high priority interrupt, and low priority interrupt
//vectors. However, the current Microchip USB bootloader
//examples are intended to occupy addresses 0x00-0x7FF or
//0x00-0xFFF depending on which bootloader is used. Therefore,
//the bootloader code remaps these vectors to new locations
//as indicated below. This remapping is only necessary if you
//wish to program the hex file generated from this project with
//the USB bootloader. If no bootloader is used, edit the
//usb_config.h file and comment out the following defines:
//#define PROGRAMMABLE_WITH_USB_HID_BOOTLOADER
//#define PROGRAMMABLE_WITH_USB_LEGACY_CUSTOM_CLASS_BOOTLOADER

#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
#define REMAPPED_RESET_VECTOR_ADDRESS 0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x1018
#elif defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
#define REMAPPED_RESET_VECTOR_ADDRESS 0x800
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x808
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x818
#else
#define REMAPPED_RESET_VECTOR_ADDRESS 0x00
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x08
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x18
#endif

#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
extern void _startup (void); // See c018i.c in your C18 compiler dir
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
void _reset (void)
{
_asm goto _startup _endasm
}
#endif
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
void Remapped_High_ISR (void)
{
_asm goto YourHighPriorityISRCode _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
void Remapped_Low_ISR (void)
{
_asm goto YourLowPriorityISRCode _endasm
}

#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_MCHPUSB_BOOTLOADER)
//Note: If this project is built while one of the bootloaders has
//been defined, but then the output hex file is not programmed with
//the bootloader, addresses 0x08 and 0x18 would end up programmed with 0xFFFF.
//As a result, if an actual interrupt was enabled and occured, the PC would jump
//to 0x08 (or 0x18) and would begin executing "0xFFFF" (unprogrammed space). This
//executes as nop instructions, but the PC would eventually reach the REMAPPED_RESET_VECTOR_ADDRESS
//(0x1000 or 0x800, depending upon bootloader), and would execute the "goto _startup". This
//would effective reset the application.

//To fix this situation, we should always deliberately place a
//"goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS" at address 0x08, and a
//"goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS" at address 0x18. When the output
//hex file of this project is programmed with the bootloader, these sections do not
//get bootloaded (as they overlap the bootloader space). If the output hex file is not
//programmed using the bootloader, then the below goto instructions do get programmed,
//and the hex file still works like normal. The below section is only required to fix this
//scenario.
#pragma code HIGH_INTERRUPT_VECTOR = 0x08
void High_ISR (void)
{
_asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18
void Low_ISR (void)
{
_asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
#endif //end of "#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)||defined(PROGRAMMABLE_WITH_USB_LEGACY_CUSTOM_CLASS_BOOTLOADER)"

#pragma code


//These are your actual interrupt handling routines.
#pragma interrupt YourHighPriorityISRCode
void YourHighPriorityISRCode()//---------------------------------------------------------------------
{
//Check which interrupt flag caused the interrupt.
//Service the interrupt
//Clear the interrupt flag
//Etc.
#if defined(USB_INTERRUPT)
USBDeviceTasks();
mLED_1_Toggle();
#endif

if(INTCONbits.TMR0IF){
//LATBbits.LATB3 ^= 1; //Toggle portB pin 3 (red LED)
mLED_2_Toggle();
INTCONbits.TMR0IF = 0; //clear the interrupt flag so that another interrupt can happen

TMR0L = 0x0; //re-initialise timer0
}
} //This return will be a "retfie fast", since this is in a #pragma interrupt section

potter68
Posts: 1
Joined: Mon Jul 22, 2013 1:39 pm

Re: Using internal oscillator to blink UBW lights

Post by potter68 » Mon Jul 22, 2013 1:41 pm

Hi,

what demo do you use? Generic HID?

Best regards, Potter

bsagan
Posts: 39
Joined: Fri Jun 28, 2013 4:31 pm

Re: Using internal oscillator to blink UBW lights

Post by bsagan » Tue Jul 23, 2013 11:17 am

This just came up in a different section of this forum: never put a function call inside an interrupt. Interrupt routines should be short and simple. They need to run quickly (so no complicated math either if possible) so that they don't interfere with the rest of your running code. One way to quickly work around this is to have a simple flag bit that you set in the interrupt routine. In your main, you have an if statement that responds when that flag bit is set. This way you don't sit in the interrupt routine for long periods of time. I think you are already thinking of doing this.

WDT (watchdog timer) is for some specific applications. It resets the PIC every overflow which prevents the PIC from getting stuck in a code loop. You will want it off for most applications.

TBH, I don't and won't understand all these configurations unless I go through the datasheet in depth. I don't quite get why it's so complicated though. A LED toggle program should be ridiculously short. I guess they are all specific configuration settings for the board?

Debugging PICs isn't the easiest of tasks. If you're not familiar with your debugger, I would use an output pin/s to debug. First thing in your setup code, set an unused pin to output and turn it on. Run your code and probe that pin; if its high, then you know your code ran past the turning on of that pin. If it's low, you know that you never got to that particular line of code. Hope I'm helping a little haha, kinda rambling at this point.

Ultima
Posts: 12
Joined: Wed Dec 26, 2012 4:39 am

Re: Using internal oscillator to blink UBW lights

Post by Ultima » Thu Jul 25, 2013 11:39 pm

Hi bsagan,

The code inside the interrupt routine is not a problem for the moment - it doesn't get executed.

I'm using the LEDS for debugging - as I said, the UBW gets stuck at:
*Flash LED*

Code: Select all

    //TRISBbits.TRISB0 = 0;    // make led pin an output     
    T0CONbits.T08BIT = 0;    // use 16 bit timer (=1 implies 8 bit)
    T0CONbits.T0CS = 0;      // use instruction cycle clock
    T0CONbits.T0PS = 255;    // timer 0 prescaler
    T0CONbits.TMR0ON =1;     // timer 0 enable
    INTCONbits.GIE = 1;      // global interrupt enable
    INTCONbits.TMR0IF = 0;   // clear timer 0 interrupt flag
    INTCONbits.TMR0IE = 1;   // enable the timer 0 interrupt
*Flash LED*

But what I'll do now is try to home in on the exact line that is the culprit (moving the second *Flash LED* up line by line)

Ultima
Posts: 12
Joined: Wed Dec 26, 2012 4:39 am

Re: Using internal oscillator to blink UBW lights

Post by Ultima » Sat Jul 27, 2013 2:57 pm

Ok, so I have made some headway. I thought the PIC was getting stuck in the code I mentioned in the previous post partly because I didn't seem able to change an LED's status. It turns out that the USB_INTERRUPT is happening so frequently that the LED looks like it is constantly on (when I added a delay after USBDeviceTasks(), it flashed a few times and then disconnected).

This also appears to be the case for timer interrupt - when I added a delay here I found out that the LED is in fact blinking!

Code: Select all

	#pragma interrupt YourHighPriorityISRCode
	void YourHighPriorityISRCode()//---------------------------------------------------------------------
	{
		//Check which interrupt flag caused the interrupt.
		//Service the interrupt
		//Clear the interrupt flag
		//Etc.
        #if defined(USB_INTERRUPT)
	        USBDeviceTasks();
		mLED_1_Toggle();
        #endif

		 if(INTCONbits.TMR0IF){
			mLED_2_Toggle();
			INTCONbits.TMR0IF = 0; //clear the interrupt flag so that another interrupt can happen
			
			TMR0L = 0x0;   //re-initialise timer0 
		}
	}	//This return will be a "retfie fast", since this is in a #pragma interrupt section 
Now I will try to work out why it was going at such a rate.

Post Reply