View previous topic :: View next topic |
Author |
Message |
123_CCS
Joined: 02 Oct 2017 Posts: 10
|
Sleep mode for PIC 24HJ64GP504 |
Posted: Mon Oct 02, 2017 9:20 am |
|
|
Hello,
I want to make use of the sleep mode.
When a Pin is made high (RC5 pin38) the uC must wake up .
When there is can-bus traffic the uc must also wake up.
Can some one please tell me what to read to achieve this?
thanks for the help |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19523
|
|
Posted: Mon Oct 02, 2017 9:31 am |
|
|
You'd have to map one of the input capture peripherals to C5 using PPS, then you can use the corresponding input capture interrupt to wake.
On the CAN, a lot depends on the nature of the traffic. If you put the module fully to sleep', it requires some time to wake after a signal is seen on the bus. The alternative it to put all other peripherals to sleep, and keep the peripheral clock running (idle mode), which then means that CAN traffic can be interpreted normally. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Oct 02, 2017 10:00 am |
|
|
Indeed, the CAN peripheral has to stay fully operational. This is a situation where hardware filtering could be advantageous so that the CAN peripheral only wakes up the processor, i.e. interrupts, when a relevant message is received instead of on every message. Getting that to work is not as easy as it sounds. |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Mon Oct 02, 2017 11:15 am |
|
|
The method for doing this will depend on if you can tolerate missing the first couple messages while the processor wakes up and configures the CAN peripheral. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19523
|
|
Posted: Mon Oct 02, 2017 12:57 pm |
|
|
On CAN, you have to put the module into 'disable' mode, and then when you go to sleep the module automatically goes into recessive mode on the bus. When there is bus activity, this triggers the CAN wake interrupt, and wakes the chip. At this point you have to re-activate the module. You have an option to enable a spike filter on the activity so that noise is less likely to wake it. The start of data will result in the hardware generating an overload frame on the bus, when the device does not respond in time. |
|
|
123_CCS
Joined: 02 Oct 2017 Posts: 10
|
|
Posted: Thu Oct 05, 2017 6:36 am |
|
|
Thank you all for the help so far,
It is allowed for the CAN-bus to take some time.
I started with the push button. I have got a test board with a 24HJ128GP502.
I get the idea the code needs to be different for different types of microcontrollers.
Can some please tell me what to change?
some points I do not understand are:
-how can I map a pin?
-Must I use
enable_interrupts(INTR_CN_PIN | PIN_B8);// turn on interrupts
-Or
enable_interrupts(INT_EXT0 | PIN_B8);//
-if the interrupt is executed will it start at the function below #INT_EXT0
?
when I run the code the red led starts to flash.
when I press the button the red led flashes a little bi shorter but the green led stays off
Code: | /////////////////////////////////////////////////////////////////////////
//// Used this example: EX_WAKUP.C ////
//// ////
//// This example shows how to use the sleep function. When the ////
//// button is pushed, the processor goes into sleep mode. When ////
//// the button is released, the processor wakes up and continues ////
//// counting. ////
//// Was counting, made it flashing the red led
/////////////////////////////////////////////////////////////////////////
/************************************************************************
My comment:
-Use Dill version = 24HJ128GP502.h
-One red led on RB7
-One green led on RB6
-One switch on RB6
GOAL:
button pressed led flashes ON / OFF
When released go to sleep.
************************************************************************/
#include <24HJ128GP502.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=24000000)
// global flag to send processor into sleep mode
short sleep_mode;
// external interrupt when button pushed and released
#INT_EXT0 //*** need INTR_CN_PIN ??
void ext_isr() {
static short button_pressed=FALSE;
output_high(pin_B6);
if(!button_pressed) // if button action and was not pressed
{
button_pressed=TRUE; // the button is now down
sleep_mode=TRUE; // activate sleep
// printf("The processor is now sleeping.\r\n");
ext_int_edge(L_TO_H); // change so interrupts on release
}
else // if button action and was pressed
{
button_pressed=FALSE; // the button is now up
sleep_mode=FALSE; // reset sleep flag
ext_int_edge(H_TO_L); // change so interrupts on press
}
if(!input(PIN_B8)) // keep button action sychronized wth button flag
button_pressed=TRUE;
//*********Button uses PULL-up to Vcc
//*********HIGH != pressed
//*********LOW = pressed
//if(!input(PIN_B8)) // keep button action sychronized wth button flag
// button_pressed=TRUE;
delay_ms(100); // debounce button
}
void main() {
sleep_mode=FALSE; // init sleep flag
//**********bevestigd ook pull up
ext_int_edge(H_TO_L); // init interrupt triggering for button press
enable_interrupts(INTR_CN_PIN | PIN_B8);// turn on interrupts
// enable_interrupts(INT_EXT0 | PIN_B8);//
enable_interrupts(GLOBAL);
while(TRUE)
{
if(sleep_mode) // if sleep flag set
sleep(); // make processor sleep
// printf("The count value is: %5ld \r\n",counter);
// counter++; // display count value and increment
output_low(pin_B7);
delay_ms(400);
output_high(pin_B7);
delay_ms(800); // every second
}
}
|
Hope you guys can help! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19523
|
|
Posted: Thu Oct 05, 2017 7:04 am |
|
|
The example for this is ex_cni.c
This is the input change peripheral. Nothing to do with INT_EXT.
They show how to map the peripheral to up to three pins at the same time (so it'd trigger on any of them), but you need only one of the sections shown. |
|
|
123_CCS
Joined: 02 Oct 2017 Posts: 10
|
|
Posted: Thu Oct 12, 2017 2:50 am |
|
|
Ttelmah wrote: | The example for this is ex_cni.c
This is the input change peripheral. Nothing to do with INT_EXT.
They show how to map the peripheral to up to three pins at the same time (so it'd trigger on any of them), but you need only one of the sections shown. |
Thank you so much! This is the example I was looking for it works like a charm!
Is there similar example for the CAN-bus sleep/wake-up ? On a PIC24? |
|
|
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
|
Posted: Thu Oct 12, 2017 4:43 am |
|
|
You should be able to use the same trick to monitor the CAN data line and wake up on message. You need to configure the CAN RX data pin to be an external interrupt during sleep and reconfigure it to be CANRX on wake up. However, bear in mind that whatever sends the message will not get an ACK until the unit wakes up. This will cause it to resend an active error frame and the message 16 times before becoming error passive. Your code will need to deal with this. Sending an RTR to the original sender once your unit is awake should sort this out.
We have had some CAN devices that either never go error passive or go beyond to error bus shutdown when not ACKed so you might want to try this out with a CAN monitor. |
|
|
123_CCS
Joined: 02 Oct 2017 Posts: 10
|
|
Posted: Mon Oct 16, 2017 6:39 am |
|
|
turpin62 wrote: | You should be able to use the same trick to monitor the CAN data line and wake up on message. You need to configure the CAN RX data pin to be an external interrupt during sleep and reconfigure it to be CANRX on wake up. However, bear in mind that whatever sends the message will not get an ACK until the unit wakes up. This will cause it to resend an active error frame and the message 16 times before becoming error passive. Your code will need to deal with this. Sending an RTR to the original sender once your unit is awake should sort this out.
We have had some CAN devices that either never go error passive or go beyond to error bus shutdown when not ACKed so you might want to try this out with a CAN monitor. |
Thank you Turpin62!
I will give it a try, The first message can be lost I understand this and this will not cause any problems.
The wake-up for the button is working fine now and I use:
#INT_CNI
void CCNI_Interrupt()
{
....
....
}
As an interrupt routine.
Think for the CANbus I need one of the interrupts as defined in the header file:
#define INT_C1RX 99
#define INT_CAN1 100
Thing I do not understand is in the datasheet this interrupt has got number which is different compared to the datasheet. The datasheet states on page 71 the numbers:
42 0x000058 0x000158 C1RX – ECAN1 RX Data Ready
43 0x00005A 0x00015A C1 – ECAN1 Event
Can some one explain which one I need and why the numbers are different? |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Oct 16, 2017 7:13 am |
|
|
Quote: |
Can some one explain which one I need and why the numbers are different? |
Explain why you think they should be the same?
INT_CAN1 is a generic interrupt vector for all functions of CAN1. I use it becuase I have both receive and transmit interrupts in my code and implement my own buffering. Note that with these PIC24s, the CAN peripheral is considerably more complex and flexible than that fitted to 18 and 16 PICs. I had to completely rethink my CAN support code for the 24s.
My INT_CAN1 handler is:
Code: |
#INT_CAN1
void can1_isr(void)
{
// Receive interrupt. Hopefully fixes receive buffering bug that
// occasionally dropped incoming messages due to reading the FIFO asynchronously wrt the hardware.
if (C1INTF.rbif)
{
// Receive interrupt - one or more messages are available for us to read.
// Note
Receive_CAN_Message();
}
/*
// Error interrupt shown for reference only. NOT used on this code.
if (C1INTF.errif)
{
// Some error has occurred.
}
*/
if (C1INTF.tbif)
{
// A transmit interrupt has occurred on buffer 0. A message has been transmitted.
// This is a combined interrupt service routine, dealing with all sources of interrupts
// from the CAN peripheral. That's fine, but on previous PICs its used just for receive, and for
// that the CCS handler deals with the receive interrupt bits for us. However. we are using
// it for transmit as well, and the CCS code DOESN'T clear the transmit interrupt bit for us, we have
// do it:
C1INTF.tbif = 0;
// Is there a buffered message to waiting to be transmitted?
Send_Next_Message();
}
}
|
I buffer in firmware on transmit (and only use one hardware transmit buffer) to allow me to throttle transmission to avoid hogging the bus, and most importantly to ensure in-order transmission.
If your code receives mostly and only occasionally transmits and message order is not significant, then you can probably use just INT_C1RX which only fires when a valid message, accepted by the hardware filters, arrives. |
|
|
123_CCS
Joined: 02 Oct 2017 Posts: 10
|
|
Posted: Thu Oct 19, 2017 2:35 am |
|
|
Ttelmah wrote: | On CAN, you have to put the module into 'disable' mode, and then when you go to sleep the module automatically goes into recessive mode on the bus. When there is bus activity, this triggers the CAN wake interrupt, and wakes the chip. At this point you have to re-activate the module. You have an option to enable a spike filter on the activity so that noise is less likely to wake it. The start of data will result in the hardware generating an overload frame on the bus, when the device does not respond in time. |
I tried this but something goes wrong.
made a simple function when you press a button it does:
can_set_mode(CAN_OP_DISABLE);
output_high(DEBUG_LED);
sleep();
The strange thing is it will never reach the setting of the debug-led, the led is never turned on. when I remove the CAN_OP_DISABLE, the led is put in a ON state and the sleep mode is activated.
my can_init is the standard CCS can_init(); There is a 120R resistor between CAN-H and CAN-L
I also tried the CAN_OP_CONFIG mode which got me the same results.
anyone got a idea what I might be doing wrong? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19523
|
|
Posted: Thu Oct 19, 2017 2:54 am |
|
|
Is the bus idle?.
It'll only go into disable mode after 11 recessive bits on the bus.
Quote: |
If the REQOP<2:0> bits (CiCTRL1<10:8>) = 001, the
module enters the Module Disable mode. If the module is
active, the module waits for 11 recessive bits on the CAN
bus, detect that condition as an Idle bus, then accept the
module disable command. When the OPMODE<2:0>
bits (CiCTRL1<7:5>) = 001, that indicates whether the
module successfully went into Module Disable mode.
The I/O pins reverts to normal I/O function when the
module is in the Module Disable mode.
|
The disable command waits for the bits to switch to the disable mode before it'll exit.
What voltage is on your bus?.
Now it should be recessive if undriven (<0.6v between CanH and CanL). There should be 120R at each end of the bus. |
|
|
123_CCS
Joined: 02 Oct 2017 Posts: 10
|
|
Posted: Thu Oct 19, 2017 3:21 am |
|
|
Ttelmah wrote: | Is the bus idle?.
It'll only go into disable mode after 11 recessive bits on the bus.
Quote: |
If the REQOP<2:0> bits (CiCTRL1<10:8>) = 001, the
module enters the Module Disable mode. If the module is
active, the module waits for 11 recessive bits on the CAN
bus, detect that condition as an Idle bus, then accept the
module disable command. When the OPMODE<2:0>
bits (CiCTRL1<7:5>) = 001, that indicates whether the
module successfully went into Module Disable mode.
The I/O pins reverts to normal I/O function when the
module is in the Module Disable mode.
|
The disable command waits for the bits to switch to the disable mode before it'll exit.
What voltage is on your bus?.
Now it should be recessive if undriven (<0.6v between CanH and CanL). There should be 120R at each end of the bus. |
There is only this can node with a 120R connected to the canbus. Nothing else. With nothing else I mean it is the only CAN-device on the bus. I did measure the voltage on the CAN-high and the CAN-low. they are both 2.305V, This is a recessive state according to the datasheet of the CAN driver. Voltage on the RDX pin of the microcontroller is 3.3V all the time. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19523
|
|
Posted: Thu Oct 19, 2017 4:03 am |
|
|
OK. Yes if the delta V between the lines is <0.6v this is the recessive state.
You don't show what is in front of this code?. You do realise you have to switch to config mode _before_ you can switch to disable_mode?.
The config mode acts like a 'lock' for any other mode change. |
|
|
|