The code below is an example of how to use the real time clock on an mcu.
My question is in relation to callbacks and function pointers.
I have included the struct declaration for rtc_config_t below.
My question is, on the line cfg.callback = rtc_example_callback
Why is the & sign not used before rtc_example_callback.
Why is not necessary to pass the arguments to rtc_example_callback?
The last struct memeber void *callback_data; is set to NULL, I don't understand what this does?
When or what would you want to return?
Many tanks for your inputs
#include "rtc.h"
#include "interrupt.h"
#include "isr.h"
#define ALARM (QM_RTC_ALARM_MINUTE / 6)
#define MAX_RTC_FIRINGS (5)
void rtc_example_callback(void *);
static volatile uint32_t rtc_fired = 0;
/* RTC app example */
int main(void)
{
/* Variables */
rtc_config_t cfg; //create a struct variable to configure the RTC
PRINTF("Starting: RTC\n");
/* Initialise RTC configuration */
cfg.init_val = 0;
cfg.alarm_en = true;
cfg.alarm_val = ALARM;
cfg.callback = rtc_example_callback;
cfg.callback_data = NULL;
irq_request(IRQ_RTC_0, rtc_isr_0); //submit the RTC to the interrupt service routine
clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); //switch on RTC and Periphal clock
rtc_set_config(RTC_0, &cfg); //Set the RTC configuration
/* Wait for RTC to fire 5 times and then finish. */
while (rtc_fired < MAX_RTC_FIRINGS) {
}
PRINTF("Finished: RTC\n");
clk_periph_disable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); //turn off the clocks
return 0;
}
void rtc_example_callback(void *data)
{
PUTS("Alarm!!\n");
qm_rtc_set_alarm(RTC_0, (RTC[RTC_0].rtc_ccvr + ALARM));
rtc_fired++;
}
-----------------------------------------------------------------------
/**
* RTC configuration type.
*/
typedef struct {
uint32_t init_val; /**< Initial value in RTC clocks. */
bool alarm_en; /**< Alarm enable. */
uint32_t alarm_val; /**< Alarm value in RTC clocks. */
/**
* User callback.
*
* #param[in] data User defined data.
*/
void (*callback)(void *data);
void *callback_data; /**< Callback user data. */
} rtc_config_t;
name of the function is a pointer to the function
function will be called with arguments from rtc library, you are not invoking it (you cannot pass arguments here).
I guess that NULL assigned to custom_callback will not call custom method from library (default function or no function will be called), just assign NULL if you dont want to use custom callback.
usually library code looks like:
if(custom_callback)
{
custom_callback(some_parameters);
}
else
{
default_callback(some_parameters);
}
Related
I'm writing a pseudo-driver to emulate a piece of hardware that does not yet exist. The pseudo driver will emulate some of the functionality of the hardware (obviously lying about actual underlying data). This is to test other parts of the system while waiting on hardware.
Obviously the actual hardware will have a valid parent device (it will be on a PCI bus, or USB, or something else), but my emulated device isn't hosted by any of these. However, I am not writing a top level device.
Driver registration requires a pointer to a struct device *parent. How do I get this information for a virtual driver?
You could allocate a dummy platform device and set up a platform device driver for testing typical driver "probe" and "remove" functionality. Here is a somewhat minimal example:
// SPDX-License-Identifier: GPL-2.0 OR MIT
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
MODULE_AUTHOR("Ian Abbott");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_DESCRIPTION("FooBar driver example with dummy platform device");
#define FOOBAR_NAME "foobar"
/* Private data for a foobar device. */
struct foobar_private {
/* ... */
struct device *hwdev; /* Pointer to hardware device. */
/* ... */
};
static int foobar_platform_probe(struct platform_device *pdev)
{
struct device *hwdev = &pdev->dev;
struct foobar_private *foobar;
dev_info(hwdev, "probe\n");
/* Allocate private data. */
foobar = kzalloc(sizeof(*foobar), GFP_KERNEL);
if (!foobar)
return -ENOMEM;
/* Set up private data. */
foobar->hwdev = hwdev;
/* Link private data to hardware device. */
dev_set_drvdata(hwdev, foobar);
/* ... other stuff ... */
return 0;
}
static int foobar_platform_remove(struct platform_device *pdev)
{
struct device *hwdev = &pdev->dev;
struct foobar_private *foobar = dev_get_drvdata(hwdev);
dev_info(hwdev, "remove\n");
dev_set_drvdata(hwdev, NULL);
/* ... other stuff ... */
kfree(foobar);
return 0;
}
/* Platform driver. */
static struct platform_driver foobar_driver = {
.probe = foobar_platform_probe,
.remove = foobar_platform_remove,
.driver = {
.name = FOOBAR_NAME,
.owner = THIS_MODULE,
},
};
/* Pointer to dummy platform device for testing purposes. */
static struct platform_device *foobar_test_device;
static int __init foobar_init(void)
{
int err;
/* Register the platform driver. */
err = platform_driver_register(&foobar_driver);
if (err)
return err;
/*
* Create a dummy platform device for testing.
* Make the platform device name the same as the driver name
* so that the driver's "probe" function will be called when
* the device is registered later.
*
* Note: PLATFORM_DEVID_AUTO allocates an "automatic" instance
* ID for the device. Can use PLATFORM_DEVID_NONE for no instance
* ID (for a single device), or use a non-zero integer to set a
* specific instance ID.
*/
foobar_test_device =
platform_device_alloc(FOOBAR_NAME, PLATFORM_DEVID_AUTO);
if (!foobar_test_device) {
err = -ENOMEM;
goto err_unregister_driver;
}
/*
* Can call functions such as platform_device_add_resources(),
* platform_device_add_data(), platform_device_add_properties(),
* etc. here for playing around.
*/
/*
* Add (register) the dummy platform device.
* This should result in the driver's "probe" function being called.
*/
err = platform_device_add(foobar_test_device);
if (err)
goto err_free_device;
return 0;
err_free_device:
/* Undo platform_device_alloc(). */
platform_device_put(foobar_test_device);
err_unregister_driver:
/* Undo platform_driver_register(). */
platform_driver_unregister(&foobar_driver);
return err;
}
static void __exit foobar_exit(void)
{
/*
* Unregister the dummy platform device used for testing.
* This should result in the driver's "remove" function being called.
*/
platform_device_unregister(foobar_test_device);
/* Unregister the platform driver. */
platform_driver_unregister(&foobar_driver);
}
module_init(foobar_init);
module_exit(foobar_exit);
If the struct platform_device's dev.parent member is NULL, platform_device_add() will change it to &platform_device.
I am looking at the Linux 4.14 kernel's include/linux/clk.h file, and have noticed that some of the functions are declared, and then later defined to return 0 or NULL.
For example:
struct clk *clk_get(struct device *dev, const char *id);
...
static inline struct clk *clk_get(struct device *dev, const char *id)
{
return NULL;
}
What is the purpose of doing this? I see multiple C source files that fully define this function and still include linux/clk.h.
Linux kernel comes with lots of configuration parameters. For this particular function, you get the service if CONFIG_HAVE_CLK parameter is defined:
#ifdef CONFIG_HAVE_CLK
/**
* clk_get - lookup and obtain a reference to a clock producer.
* #dev: device for clock "consumer"
* #id: clock consumer ID
*
* Returns a struct clk corresponding to the clock producer, or
* valid IS_ERR() condition containing errno. The implementation
* uses #dev and #id to determine the clock consumer, and thereby
* the clock producer. (IOW, #id may be identical strings, but
* clk_get may return different clock producers depending on #dev.)
*
* Drivers must assume that the clock source is not enabled.
*
* clk_get should not be called from within interrupt context.
*/
struct clk *clk_get(struct device *dev, const char *id);
[...]
#else /* !CONFIG_HAVE_CLK */
static inline struct clk *clk_get(struct device *dev, const char *id)
{
return NULL;
}
[...]
This parameter is defined in arch/Kconfig as:
config HAVE_CLK
bool
help
The <linux/clk.h> calls support software clock gating and
thus are a key power management tool on many systems.
I have made a custom kernel module to handle rising edge triggered interrupts on a GPIO. I want to make a "uio" file for the same in /dev directory. What must I do? Do I need to declare some structures and fill it out ? It would be good if someone could share relevant examples.
Below is the code snippet for the cutom GPIO driver that triggers interrupts.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h> // Required for the GPIO functions
#include <linux/interrupt.h> // Required for the IRQ code
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Khilav Soni");
MODULE_DESCRIPTION("A Switch test driver");
static unsigned int gpio_switch = 65; ///< hard coding the button gpio for this example to P9_27 (GPIO65)
static unsigned int irq_number; ///< Used to share the IRQ number within this file
/// Function prototype for the custom IRQ handler function -- see below for the implementation
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);
/** #brief The LKM initialization function
* The static keyword restricts the visibility of the function to within this C file. The __init
* macro means that for a built-in driver (not a LKM) the function is only used at initialization
* time and that it can be discarded and its memory freed up after that point. In this example this
* function sets up the GPIOs and the IRQ
* #return returns 0 if successful
*/
static int __init ebbgpio_init(void){
int result = 0;
printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n");
gpio_request(gpio_switch, "sysfs"); // Set up the gpioButton
gpio_direction_input(gpio_switch); // Set the button GPIO to be an input
gpio_set_debounce(gpio_switch, 100); // Debounce the button with a delay of 200ms
//gpio_export(gpio_switch, false); // Causes gpio115 to appear in /sys/class/gpio
// the bool argument prevents the direction from being changed
// Perform a quick test to see that the button is working as expected on LKM load
printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpio_switch));
// GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
irq_number = gpio_to_irq(gpio_switch);
printk(KERN_INFO "GPIO_TEST: The button is mapped to IRQ: %d\n", irq_number);
// This next call requests an interrupt line
result = request_irq(irq_number, // The interrupt number requested
(irq_handler_t) ebbgpio_irq_handler, // The pointer to the handler function below
IRQF_TRIGGER_RISING, // Interrupt on rising edge (button press, not release)
"switch-event", // Used in /proc/interrupts to identify the owner
NULL); // The *dev_id for shared interrupt lines, NULL is okay
printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result);
return result;
}
/** #brief The LKM cleanup function
* Similar to the initialization function, it is static. The __exit macro notifies that if this
* code is used for a built-in driver (not a LKM) that this function is not required. Used to release the
* GPIOs and display cleanup messages.
*/
static void __exit ebbgpio_exit(void){
free_irq(irq_number, NULL); // Free the IRQ number, no *dev_id required in this case
gpio_unexport(gpio_switch); // Unexport the Button GPIO
gpio_free(gpio_switch); // Free the Button GPIO
}
/** #brief The GPIO IRQ Handler function
* This function is a custom interrupt handler that is attached to the GPIO above. The same interrupt
* handler cannot be invoked concurrently as the interrupt line is masked out until the function is complete.
* This function is static as it should not be invoked directly from outside of this file.
* #param irq the IRQ number that is associated with the GPIO -- useful for logging.
* #param dev_id the *dev_id that is provided -- can be used to identify which device caused the interrupt
* Not used in this example as NULL is passed.
* #param regs h/w specific register values -- only really ever used for debugging.
* return returns IRQ_HANDLED if successful -- should return IRQ_NONE otherwise.
*/
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs){
static unsigned int numberPresses = 0; ///< For information, store the number of button presses
printk(KERN_INFO "GPIO_TEST: Interrupt! (button state is %d)\n", gpio_get_value(gpio_switch));
printk(KERN_INFO "GPIO_TEST: The button was pressed %d times\n", numberPresses);
numberPresses++; // Global counter, will be outputted when the module is unloaded
return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly
}
/// This next calls are mandatory -- they identify the initialization function
/// and the cleanup function (as above).
module_init(ebbgpio_init);
module_exit(ebbgpio_exit);
My first question here. I´m no proffesional programmer at all. Just for fun at home so I don´t really know the right terminology for what I´m about to ask.
I want to create a CAN-bus gateway and I have the NXP DEVKIT-MPC5748G. All the CAN-busses are set-up and working for both tx and rx. Now I want to create a function for manipulating the different CAN-controllers. Theres 8 of them so I was hoping of not write 8 equal functions only having what CAN-controller to use differ.
You setup the controllers like this:
CAN_1.CTRL1.B.CLKSRC = 0;
Just an example for setting the clock source.
CAN_1 has a macro like this:
#define CAN_1 (*(volatile struct CAN_1_7_tag *) 0xFBEC0000UL)
In that struct there is a hole lot of unions for accessing all the registers. Now I want to write a function that I can pass a parameter to tell what CAN-controller to use. I can use a switch/case style way of doing it but that code will be long and ugly.
I want to do something like this:
void Tx_Msg("type???" gwport, int mb, uint32_t id) {
gwport.[mb].CS.B.CODE = 0x8; }
But I cant figure out how to do it. Can it be done?
Thankfull for all help in the right direction. :)
Best regards, Joakim
EDIT to clarify
CAN_1_7_tag struct:
struct CAN_1_7_tag {
CAN_MCR_tag MCR; /* Module Configuration Register */
CAN_CTRL1_tag CTRL1; /* Control 1 register */
CAN_TIMER_tag TIMER; /* Free Running Timer */
uint8_t CAN_reserved0[4];
CAN_RXMGMASK_tag RXMGMASK; /* Rx Mailboxes Global Mask Register */
CAN_RX14MASK_tag RX14MASK; /* Rx 14 Mask register */
CAN_RX15MASK_tag RX15MASK; /* Rx 15 Mask register */
CAN_ECR_tag ECR; /* Error Counter */
CAN_ESR1_tag ESR1; /* Error and Status 1 register */
CAN_IMASK2_tag IMASK2; /* Interrupt Masks 2 register */
CAN_IMASK1_tag IMASK1; /* Interrupt Masks 1 register */
CAN_IFLAG2_tag IFLAG2; /* Interrupt Flags 2 register */
CAN_IFLAG1_tag IFLAG1; /* Interrupt Flags 1 register */
CAN_CTRL2_tag CTRL2; /* Control 2 register */
CAN_ESR2_tag ESR2; /* Error and Status 2 register */
uint8_t CAN_reserved1[8];
CAN_CRCR_tag CRCR; /* CRC Register */
CAN_RXFGMASK_tag RXFGMASK; /* Rx FIFO Global Mask register */
CAN_RXFIR_tag RXFIR; /* Rx FIFO Information Register */
CAN_CBT_tag CBT; /* CAN Bit Timing Register */
uint8_t CAN_reserved2[24];
CAN_IMASK3_tag IMASK3; /* Interrupt Masks 3 Register */
uint8_t CAN_reserved3[4];
CAN_IFLAG3_tag IFLAG3; /* Interrupt Flags 3 Register */
uint8_t CAN_reserved4[8];
CAN_MB_tag MB[64];
uint8_t CAN_reserved5[1024];
CAN_RXIMR_tag RXIMR[96]; /* Rx Individual Mask Registers */
uint8_t CAN_reserved6[512];
CAN_FDCTRL_tag FDCTRL; /* CAN FD Control Register */
CAN_FDCBT_tag FDCBT; /* CAN FD Bit Timing Register */
CAN_FDCRC_tag FDCRC; /* CAN FD CRC Register */
};
Example for MCR register. All registers works the same way.
typedef union CAN_MCR_union_tag { /* Module Configuration Register */
vuint32_t R;
struct {
vuint32_t MDIS:1; /* Module Disable */
vuint32_t FRZ:1; /* Freeze Enable */
vuint32_t RFEN:1; /* Rx FIFO Enable */
vuint32_t HALT:1; /* Halt FlexCAN */
vuint32_t NOTRDY:1; /* FlexCAN Not Ready */
vuint32_t WAKMSK:1; /* Wake Up Interrupt Mask */
vuint32_t SOFTRST:1; /* Soft Reset */
vuint32_t FRZACK:1; /* Freeze Mode Acknowledge */
vuint32_t SUPV:1; /* Supervisor Mode */
vuint32_t SLFWAK:1; /* Self Wake Up */
vuint32_t WRNEN:1; /* Warning Interrupt Enable */
vuint32_t LPMACK:1; /* Low-Power Mode Acknowledge */
vuint32_t WAKSRC:1; /* Wake Up Source */
vuint32_t _unused_18:1;
vuint32_t SRXDIS:1; /* Self Reception Disable */
vuint32_t IRMQ:1; /* Individual Rx Masking And Queue Enable */
vuint32_t DMA:1; /* DMA Enable */
vuint32_t _unused_14:1;
vuint32_t LPRIOEN:1; /* Local Priority Enable */
vuint32_t AEN:1; /* Abort Enable */
vuint32_t FDEN:1; /* CAN FD operation enable */
vuint32_t _unused_10:1;
vuint32_t IDAM:2; /* ID Acceptance Mode */
vuint32_t _unused_7:1;
vuint32_t MAXMB:7; /* Number Of The Last Message Buffer */
} B;
} CAN_MCR_tag;
Hope this is what you asked for.
If CAN_1 is define as:
#define CAN_1 (*(volatile struct CAN_1_7_tag *) 0xFBEC0000UL)
Then CAN_1 is a structure of type CAN_1_7_tag which is located at 0xFBEC0000UL.
The volatile qualifier is here to indicate to the compiler that is should not optimize anything relatives to the CAN_1 as it might be changed by other threads.
You can pass the CAN-controller as a pointer:
void Tx_Msg(volatile struct CAN_1_7_tag *p_gwport, int mb, uint32_t id)
{
p_gwport->CTRL1.B.CLKSRC = 0;
p_gwport->MB[mb].CS.B.CODE = 0x8;
}
Then when calling this function to send a message from a specific CAN-controller, you can use:
Tx_Msg(&CAN_1, 12, 25);
Tx_Msg(&CAN_4, 21, 45);
Thanks one more time for the help. The CAN gateway is up and running as a prototype.
This is my "final" code.
/********************************************************************************/
/* Tx function for FlexCAN 1-7 */
/********************************************************************************/
void Tx_Msg_1_7(volatile struct CAN_1_7_tag *port, uint32_t mb, uint32_t dlc, uint32_t id, uint8_t txData[])
{
int i = 0; // Used in for loops
port->MB[mb].CS.B.CODE = 0x8; // MB TX inactive
port->MB[mb].CS.B.DLC = dlc; // Message length max 8 bytes
port->MB[mb].CS.B.RTR = 0; // Remote frame disable
port->MB[mb].CS.B.SRR = 1; // Not used with standard id
if (id > 0x7FF) // CAN id 29 bits
{
port->MB[mb].CS.B.IDE = 1; // EXT CAN id
port->MB[mb].ID.B.ID_STD = id >> 18 & 0x7FF; // CAN id (11 bits)
port->MB[mb].ID.B.ID_EXT = id & 0x3FFFF; // CAN id (18 bits)
}
else // CAN id 11 bits
{
port->MB[mb].CS.B.IDE = 0; // STD CAN id
port->MB[mb].ID.B.ID_STD = id; // CAN id (11 bits)
port->MB[mb].ID.B.ID_EXT = 0; // CAN id (18 bits), always 0
}
for(i = 0; i < dlc; i++)
{
port->MB[mb].DATA.B[i] = txData[i];
}
port->MB[mb].CS.B.CODE = 0xC; // MB once transmit data
}
The code below is related to the initialization of an RTC in an MCU.
Would anybody know the rational for passing NULL to rtc_init() and then setting a global callback global_rtc_cb equal to it.
Why would you use a global callback at all when there is an other function called rtc_callback defined and used as the callback in the struct.
int main() {
rtc_init(NULL);
}
//-----------------------------------------------------------------
void ( * global_rtc_cb)(void *);
int rtc_init(void (*cb)(void *)) {
rtc_config_t cfg;
cfg.init_val = 0;
cfg.alarm_en = true;
cfg.alarm_val = ALARM;
cfg.callback = rtc_callback;
cfg.callback_data = NULL;
global_rtc_cb = cb;
irq_request(IRQ_RTC_0, rtc_isr_0);
clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);
rtc_set_config(QM_RTC_0, &cfg);
return 0;
}
//---------------------------------------------------------------------
/**
* RTC configuration type.
*/
typedef struct {
uint32_t init_val; /**< Initial value in RTC clocks. */
bool alarm_en; /**< Alarm enable. */
uint32_t alarm_val; /**< Alarm value in RTC clocks. */
/**
* User callback.
*
* #param[in] data User defined data.
*/
void (*callback)(void *data);
void *callback_data; /**< Callback user data. */
} rtc_config_t;
The rtc_ functions are part of the RTC driver. The RTC driver has something driver-specific to do when the event that prompts the callback occurs. This driver-specific stuff happens in rtc_callback. But there may also be other application-specific stuff that the application must do when the event occurs. The application-specific stuff should be done at the application layer, not within the driver. So if the application has something to do in response to the event it can provide a callback to rtc_init. Surely rtc_callback calls global_rtc_cb so that both the driver-specific stuff and the application-specific stuff is performed when the event occurs. Apparently your particular application doesn't need to do anything for this event so it passes NULL to rtc_init. But a different application that uses the same driver may provide a callback function.