generating EXTI0 interrupt when extenal temperature sensor is connected to STM32F207VC - sensors

I am using STM32F207VC controller . I have my external probe temperature sensor connected to one of the internal ADC channel of stm32.
I want to generate an external interrupt when this is connected to controller and i should start measuring from external temperature sensor.
Please could any one provide me code or any help in this
Thanks

I have an STM32F4 processor interfaced with a Solomon Systems SSD1963 GPU. The GPU has a Tearing Signal (TE) that notifies the processor when it is about to do a vertical refresh. I hope you can use this code as an example and adapt it to your solution.
The TE signal is connected to the CPU's GPIO G7 pin. So first I have to configure the GPIO pin.
//GPIO Pin G7
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG, &GPIO_InitStructure);
Next I have to configure the interrupt and NVIC.
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOG, EXTI_PinSource7);
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_StructInit(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = EXTI_Line7;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
Finally I have to create the interrupt handler. The EXTI9_5_IRQHandler handles external interrupts on lines 5 ~ 7. This method is actually defined in my CPUs startup assembly file as a weak reference. I just need to redefine the method and the linker will do the rest.
extern "C" void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line7) != RESET)
{
//Handle the interrupt
EXTI_ClearITPendingBit(EXTI_Line7);
}
}
I'm using Mentor Graphics' Sourcery Codebench Lite as my toolchain.

Related

STM32F3 C programming: Stuck at channel selection while implementing ADC

Short version:
Need help with C programming to select channel/s for ADC in STM32F3(Dicovery board). Please find the code that I have written as of now at the end of the question. It would be great if anyone can refer to some resources for bare metal programming.
Long Version:
I am learning programming ARM controllers; what I have is a ST32F303 Discovery board and I believe the method I am trying is called bare metal programing. I have experience in writing plain C code for AVR microcontrollers but that was quite straight forward and almost all the registers were same throughout the series. But when it came to ARM I was totally surprised to see the number of things(files) that we have to get right for even compiling the code properly. By the way I am having a Linux system so I put together the gnu arm toolchain with Eclipse.
After some research and numerous Youtube videos I finalized on two materials
STM32Snippets
NewbieHack - This chaps Youtube series which is for
Of course I am referring the reference manual of the controller in hand too. But the problem is that both of the above resources are not straight forward ones for stm32F3, But I am using the same workflow for writing for F3. Right now I am stuck with ADC as I cant figure out how to select a channel for conversion and some advice and guidance would be helpful
Here is the code I have written so far
/*
* ADC in ARM
*
* Author : Easwaran
*
*/
#include "stm32f30x_conf.h"
int main (void)
{
//ADC calibration
ADC1->CR &= ~ADC_CR_ADEN; //Disables ADC; 0 in ADCEN to disable ADC.
// ADC1->CR
ADC1->CR |= ADC_CR_ADCAL; //put a 1 in calibration register | CR is the control register for ADC1
while ((ADC1->CR & ADC_CR_ADCAL) != 0)
{
//waiting till the calibration is over; ie the bit turns 0
}
//select a clock source
RCC->AHBENR |= RCC_AHBENR_ADC12EN; // enables both ADC1 & 2
RCC->CR |= RCC_CR_HSEON;
while((RCC->CR & RCC_CR_HSERDY) != 1)
{
//to make sure the clock has started
}
ADC1->CR = ADC12_CCR_CKMODE; // this is weird
// enable ADC
ADC1-> CR = ADC_CR_ADEN;
while((ADC1->ISR & ADC_ISR_ADRD) == 0)
{
//waiting to get ready
}
//sampling time
ADC1->SMPR1 |= ADC_SMPR1_SMP0_0 | ADC_SMPR1_SMP0_1 | ADC_SMPR1_SMP0_2;
//set the channel - here internal temp register
while(1)
{
//start conversion
}
}

Custom SPI driver to implement lseek

I am trying to implement a SPI driver for custom hardware. I have started with a copy of the spidev driver, which has support for almost everything I need.
We're using a protocol that has three parts: a command bit (read / write) an address, and an arbitrary amount of data.
I had assumed that simply adding lseek capabilities would be the best way to do this. "Seek" to the desired address, then read or write any number of bytes. I created a custom .llseek in the new driver's file_operations, but I have never seen that function even be called. I have tried using fseek(), lseek(), and pread() and none of those functions seem to call the new my_lseek() function. Every call reports "errno 29 ESPIPE Illegal Seek"
The device is defined in the board.c file:
static struct spi_board_info my_spi_board_info[] __initdata = {
[0] = {
.modalias = "myspi",
.bus_num = 1,
.chip_select = 0,
.max_speed_hz = 3000000,
.mode = SPI_MODE_0,
.controller_data = &spidev_mcspi_config,
}, ...
I suspect there might be something with the way that the dev files get created, mainly because the example that I found references filp->f_pos
static int myspi_llseek(struct file *filp, loff_t off, int whence)
{
...
newpos = filp->f_pos + off;
...
}
So my questions are: Is there a way to have this driver (lightly modified spidev) support the "seek" call? At what point does this get defined to return errno 29? Will I have to start from a new driver and not be able to rely on the spi_board_info() and spi_register_board_info() setup?
Only one driver in the /drivers/spi directory (spi-dw) references lseek, and they use the default_llseek implementation. There are a couple of "hacks" that we've come up with to get everything up and running, but I tend to be a person who wants to learn to get it done the right way.
Any suggestions are greatly appreciated! (PS, the kernel version is 3.4.48 for an OMAP Android system)
Spi driver dose not support any llseek or fseek functionality. It has these many call back functions.
struct spi_driver {
const struct spi_device_id *id_table;
int (*probe)(struct spi_device *spi);
int (*remove)(struct spi_device *spi);
void (*shutdown)(struct spi_device *spi);
int (*suspend)(struct spi_device *spi, pm_message_t mesg);
int (*resume)(struct spi_device *spi);
struct device_driver driver;
};
Now drivers/spi/spi-dw.c is register as a charter-driver(debugfs_create_file("registers", S_IFREG | S_IRUGO,
dws->debugfs, (void *)dws, &dw_spi_regs_ops);). So they implement to create a file in the debugfs filesystem. they implement lseek callback function.
static const struct file_operations dw_spi_regs_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = dw_spi_show_regs,
.llseek = default_llseek,
};
The file_operations structure is defined in linux/fs.h, and holds pointers to functions defined by the driver that perform various operations on the device. Each field of the structure corresponds to the address of some function defined by the driver to handle a requested operation
lseek -: lseek is a system call that is used to change the location of the read/write pointer of a file descriptor.
SPI -: The "Serial Peripheral Interface" (SPI) is a synchronous four wire serial link used to connect microcontrollers to sensors, memory, and peripherals. SPI can not provide any lseek and fseek functionlity.
There are two type of SPI driver (https://www.kernel.org/doc/Documentation/spi/spi-summary)
Controller drivers ... controllers may be built into System-On-Chip
processors, and often support both Master and Slave roles.
These drivers touch hardware registers and may use DMA.
Or they can be PIO bitbangers, needing just GPIO pins.
Protocol drivers ... these pass messages through the controller
driver to communicate with a Slave or Master device on the
other side of an SPI link.
If you want to user read, write and llseek then you will have to register a charter-driver on top of SPI. Then you will able to achieve your acquirement.

Remove input driver bound to the HID interface

I'm playing with some driver code for a special kind of keyboard. And this keyboard does have special modes. According to the specification those modes could only be enabled by sending and getting feature reports.
I'm using 'hid.c' file and user mode to send HID reports. But both 'hid_read' and 'hid_get_feature_report' failed with error number -1.
I already tried detaching keyboard from kernel drivers using libusb, but when I do that, 'hid_open' fails. I guess this is due to that HID interface already using by 'input' or some driver by the kernel. So I may not need to unbind kernel hidraw driver, instead I should try unbinding the keyboard ('input') driver top of 'hidraw' driver. Am I correct?
And any idea how I could do that? And how to find what are drivers using which drivers and which low level driver bind to which driver?
I found the answer to this myself.
The answer is to dig this project and find it's hid implementation on libusb.
Or you could directly receive the report.
int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
{
int res = -1;
int skipped_report_id = 0;
int report_number = data[0];
if (report_number == 0x0) {
/* Offset the return buffer by 1, so that the report ID
will remain in byte 0. */
data++;
length--;
skipped_report_id = 1;
}
res = libusb_control_transfer(dev->device_handle,
LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
0x01/*HID get_report*/,
(3/*HID feature*/ << 8) | report_number,
dev->interface,
(unsigned char *)data, length,
1000/*timeout millis*/);
if (res < 0)
return -1;
if (skipped_report_id)
res++;
return res;
}
I'm sorry I can't post my actual code due to some legal reasons. However the above code is from hidapi implementation.
So even you work with an old kernel , you still have the chance to make your driver working.
This answers to this question too: https://stackoverflow.com/questions/30565999/kernel-version-2-6-32-does-not-support-hidiocgfeature

Atmega8 microcontroller reading from bluetooth

I want to read a byte sent by Bluetooth to the Atmega8 to process it. I found this function online to receive a byte
uint8_t receiveByte()
{
// Wait until a byte has been received
while((UCSRA&(1<<RXC)) == 0);
// Return received data
return UDR;
}
but it doesn't work by say turning a led on if 'a' was sent, so when I changed it and enabled port c to HIGH just before the while loop, and turned it low after it, but port c never gone low - which means this loop is infinite.
so my question is how to fix it or how can I read a byte from Bluetooth module
its atmega8-16pu and I configured it as follows:
/** define the cpu clock frequency*/
#define F_CPU 8000000UL
and fuse = 0xD9C4, from this site http://www.engbedded.com/fusecalc/

Unclear logic behind pl011_tx_chars() in amba-pl011 Linux kernel module

I'm trying to understand how Linux driver for AMBA serial port (amba-pl011.c) sends characters in non-DMA mode. For port operations, this driver registers only following callbacks:
static struct uart_ops amba_pl011_pops = {
.tx_empty = pl011_tx_empty,
.set_mctrl = pl011_set_mctrl,
.get_mctrl = pl011_get_mctrl,
.stop_tx = pl011_stop_tx,
.start_tx = pl011_start_tx,
.stop_rx = pl011_stop_rx,
.enable_ms = pl011_enable_ms,
.break_ctl = pl011_break_ctl,
.startup = pl011_startup,
.shutdown = pl011_shutdown,
.flush_buffer = pl011_dma_flush_buffer,
.set_termios = pl011_set_termios,
.type = pl011_type,
.release_port = pl011_release_port,
.request_port = pl011_request_port,
.config_port = pl011_config_port,
.verify_port = pl011_verify_port,
.poll_init = pl011_hwinit,
.poll_get_char = pl011_get_poll_char,
.poll_put_char = pl011_put_poll_char };
As you can see, there's no character sending operation among them, namely, pl011_tx_chars() function is not listed there. Since pl011_tx_chars() is declared static, it is not exposed outside the module. I found that within the module it is called only from pl011_int() function which is an interrupt handler. It is called whenever UART011_TXIS occurs:
if (status & UART011_TXIS) pl011_tx_chars(uap);
The function pl011_tx_chars() itself writes characters from circular buffer to UART01x_DR port until the fifo queue size is reached (function returns then so more data will be written at the next interrupt) or until circular buffer is empty (pl011_stop_tx() is called then). As we can see, pl011_start_tx() and pl011_stop_tx() are listed in AMBA port operations (so they can be called as callbacks despite their local static declaration). Seems reasonable, thing is, these two function do something very simple:
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
uap->im &= ~UART011_TXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
pl011_dma_tx_stop(uap);
}
static void pl011_start_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
if (!pl011_dma_tx_start(uap)) {
uap->im |= UART011_TXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
}
}
Since I don't have CONFIG_DMA_ENGINE set, pl011_dma_tx_start() and pl011_dma_tx_stop() are just stubs:
static inline void pl011_dma_tx_stop(struct uart_amba_port *uap)
{
}
static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
{
return false;
}
Seems like the only thing that pl011_start_tx() does is to arm UART011_TXIM interrupt while the only thing that pl011_stop_tx() does is to disarm it. Nothing initiates the transmission!
I looked at serial_core.c - it's the only file where start_tx operation is invoked, in four places (by the registered callback). The most promissing place is uart_write() function. It fills circular buffer with data and calls local static uart_start() function which is very simple:
static void __uart_start(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
!tty->stopped && !tty->hw_stopped)
port->ops->start_tx(port);
}
static void uart_start(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
__uart_start(tty);
spin_unlock_irqrestore(&port->lock, flags);
}
As you can see, no one sends initial characters to the UART port, circular buffer is filled and everything is waiting for UART011_TXIS interrupt.
Is it possible that arming UART011_TXIM interrupt instantly emits UART011_TXIS? I looked into DDI0183.pdf (PrimeCell® UART (PL011) Technical Referecne Manual), Chapter 3: Programmers Model, section 3.4: Interrupts, subsection 3.4.3 UARTTXINTR. What it says is:
....
The transmit interrupt changes state when one of the following events occurs:
• If the FIFOs are enabled and the transmit FIFO reaches the programmed trigger
level. When this happens, the transmit interrupt is asserted HIGH. The transmit
interrupt is cleared by writing data to the transmit FIFO until it becomes greater
than the trigger level, or by clearing the interrupt.
• If the FIFOs are disabled (have a depth of one location) and there is no data
present in the transmitters single location, the transmit interrupt is asserted HIGH.
It is cleared by performing a single write to the transmit FIFO, or by clearing the
interrupt.
....
The note below is even more interesting:
....
The transmit interrupt is based on a transition through a level, rather than on the level
itself. When the interrupt and the UART is enabled before any data is written to the
transmit FIFO the interrupt is not set. The interrupt is only set once written data leaves
the single location of the transmit FIFO and it becomes empty.
....
The emphasis above is mine. I don't know if my English is not sufficient, but from the words above I can't find where it states that unlocking transmit interrupt can be used for triggering transmit routine. What am I missing?
The ARM docs say that the PL011 is a "16550-ish" UART. This sort of gets them off the hook for fully specifying its behavior and instead sends you to the 16550 docs, which state in the "FIFO interrupt mode operation" section...
When the XMIT FIFO and transmitter interrupts are enabled (FCR0e1,
IER1e1), XMIT interrupts will occur as follows: A. The transmitter
holding register interrupt (02) occurs when the XMIT FIFO is empty; it
is cleared as soon as the transmitter holding register is written to
(1 to 16 characters may be written to the XMIT FIFO while servicing
this interrupt) or the IIR is read.
So, it appears that if the FIFO and TX holding register are empty and you enable TX interrupts, you should immediately see a TX interrupt that kickstarts the sending process and fills the holding register and then the FIFO. Once those drain back down below the FIFO trigger, then another interrupt will be generated to keep the process going for as long as there is more buffered data to be sent.

Resources