Linux Kernel Module to interface with GPIO module on Beaglebone Black - c

I write a Linux kernel module on Beaglebone Black to interface with GPIO module use its registers. A button connect with GPIO20, a LED connect with GPIO30 via a transistor 200 Ohm. I want when insmod kernel module then press button, LED ON and press again LED OFF, and so on. Following is my code for kernel module. My problem is when press button, LED not switch state.
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/io.h>
#include <linux/delay.h>
#define GPIO_ADDR_BASE 0X44E07000
#define ADDR_SIZE 0X1000
#define GPIO_SETDATAOUT_OFFSET 0X194
#define GPIO_CLEARDATAOUT_OFFSET 0X190
#define GPIO_OE_OFFSET 0X134
#define GPIO_DATAIN_OFFSET 0X138
// enable IRQ
#define GPIO_IRQSTATUS_RAW_0_OFFSET 0X24
// enable interrupt
#define GPIO_IRQSTATUS_SET_0_OFFSET 0X34
// define intterupt type
#define GPIO_RISINGDETECT_OFFSET 0X148
// enable debounce feature
#define GPIO_DEBOUNCENABLE_OFFSET 0X150
// set debounce time
#define GPIO_DEBOUNCINGTIME_OFFSET 0X154
#define LED_VALUE_0 ~(1 << 30)
#define LED_VALUE_1 (1 << 30)
#define BUTTON_VALUE_0 ~(1 << 20)
#define BUTTON_VALUE_1 (1 << 20)
void __iomem *base_addr;
int init_module(void)
{
uint32_t reg_data = 0;
printk(KERN_EMERG "Hello");
base_addr = ioremap(GPIO_ADDR_BASE, ADDR_SIZE);
// CONFIG for LED
/* write 0 to GPIO Pin 30 mean config this pin is output */
writel_relaxed(LED_VALUE_0, base_addr + GPIO_OE_OFFSET);
// at insert module time, led off
writel_relaxed(LED_VALUE_1, base_addr + GPIO_CLEARDATAOUT_OFFSET);
// CONFIG for BUTTON
// config button pin is GPIO input
writel_relaxed(BUTTON_VALUE_1, base_addr + GPIO_OE_OFFSET);
// active IRQ
writel_relaxed(0x1, base_addr + GPIO_IRQSTATUS_RAW_0_OFFSET);
// enable interrupt
writel_relaxed(0x1, base_addr + GPIO_IRQSTATUS_SET_0_OFFSET);
// enable rising interrupt
writel_relaxed(0x1, base_addr + GPIO_RISINGDETECT_OFFSET);
// enable debounce feature
writel_relaxed(1 << 20, base_addr + GPIO_DEBOUNCENABLE_OFFSET);
// set debounce time
writel_relaxed(0xFF, base_addr + GPIO_DEBOUNCINGTIME_OFFSET);
while (1) {
reg_data = readl_relaxed(base_addr + GPIO_DATAIN_OFFSET);
if (reg_data == 1)
{
writel_relaxed(LED_VALUE_1, base_addr + GPIO_SETDATAOUT_OFFSET);
mdelay(1000);
}
}
return 0;
}
void cleanup_module(void)
{
printk(KERN_EMERG "Goodbye");
/* off led */
writel_relaxed(LED_VALUE_1, base_addr + GPIO_CLEARDATAOUT_OFFSET);
/* config default GPIO Pin is input
* set Pin 30 to default
*/
writel_relaxed(LED_VALUE_1, base_addr + GPIO_CLEARDATAOUT_OFFSET);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Phu Luu An");
MODULE_DESCRIPTION("Hello world kernel module");

Related

Incorrect 1ms delay at GD32VF103

I use GD32VF103C_START kit from GigaDevice and try LED blinking sample project. I found this project in the Internet and it compiles just fine (I've only changed from 500ms to 1000ms=1s).
main.c:
#include "gd32vf103.h"
#include "gd32vf103c_start.h"
#include "systick.h"
int main(void)
{
/* enable the LED clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* configure LED GPIO port */
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
gpio_bit_reset(GPIOA, GPIO_PIN_7);
while(1){
/* insert 1s delay */
delay_1ms(1000);
/* toggle the LED */
gpio_bit_write(GPIOA, GPIO_PIN_7, (bit_status)(1-gpio_input_bit_get(GPIOA, GPIO_PIN_7)));
/* insert 1s delay */
delay_1ms(1000);
gpio_bit_write(GPIOA, GPIO_PIN_7, (bit_status)(1-gpio_input_bit_get(GPIOA, GPIO_PIN_7)));
}
}
systick.c:
#include "gd32vf103.h"
#include "systick.h"
void delay_1ms(uint32_t count)
{
uint64_t start_mtime, delta_mtime;
/* don't start measuruing until we see an mtime tick */
uint64_t tmp = get_timer_value();
do{
start_mtime = get_timer_value();
}while(start_mtime == tmp);
do{
delta_mtime = get_timer_value() - start_mtime;
}while(delta_mtime <(SystemCoreClock/4000.0 *count));
}
But instead of 1s delay it delays like for 13s. Where is mistake?
Problem is non in main.c, neither in systick.c, it's in system_gd32vf103.c.
There are:
/* system frequency define */
#define __IRC8M (IRC8M_VALUE) /* internal 8 MHz RC oscillator frequency */
#define __HXTAL (HXTAL_VALUE) /* high speed crystal oscillator frequency */
#define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */
/* select a system clock by uncommenting the following line */
/* use IRC8M */
//#define __SYSTEM_CLOCK_48M_PLL_IRC8M (uint32_t)(48000000)
//#define __SYSTEM_CLOCK_72M_PLL_IRC8M (uint32_t)(72000000)
//#define __SYSTEM_CLOCK_108M_PLL_IRC8M (uint32_t)(108000000)
/********************************************************************/
//#define __SYSTEM_CLOCK_HXTAL (HXTAL_VALUE)
//#define __SYSTEM_CLOCK_24M_PLL_HXTAL (uint32_t)(24000000)
/********************************************************************/
//#define __SYSTEM_CLOCK_36M_PLL_HXTAL (uint32_t)(36000000)
//#define __SYSTEM_CLOCK_48M_PLL_HXTAL (uint32_t)(48000000)
//#define __SYSTEM_CLOCK_56M_PLL_HXTAL (uint32_t)(56000000)
//#define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
//#define __SYSTEM_CLOCK_96M_PLL_HXTAL (uint32_t)(96000000)
#define __SYSTEM_CLOCK_108M_PLL_HXTAL (uint32_t)(108000000)
and you need uncomment #define __SYSTEM_CLOCK_HXTAL (HXTAL_VALUE) line. That's it.

C: Undefined reference to 'clock()' [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 4 years ago.
I'm not really that familiar with C so please bear with me...
I'm writing some simple code for a watchdog timer on an Atmel Tiny 85, developing in AtmelStudio. I want to access the clock() function of the time.h library:
#include <time.h>
.....
void main() {
clock_t start = clock();
....
}
Unfortunately the compiler complains that clock is an undefined reference. Every code example I have looked up on the web seems to be doing what I am doing. Is there some fundamental thing I am missing? Thanks!
Here is the full code:
#define F_CPU 1000000UL // 1 MHz
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <time.h>
#include <stdio.h>
#include <avr/wdt.h>
#include <stdint.h>
#include <util/atomic.h>
#define LED_PORT PB1
#define RST0_PORT PINB3
#define RST1_PORT PINB4
#define HEARTBEAT PINB0
volatile int HEARTBEAT_RECEIVED;
#define CLOCKS_PER_SECOND 1000000;
const int TIMEOUT_PERIOD = 120; //reset raspberry pi after this many seconds
void set_output();
void set_input();
void set_interrupts();
void run_timer(clock_t start);
void restart_raspberry_pi();
int main(void)
{
clock_t start;
HEARTBEAT_RECEIVED = false;
//Configure IO pins
set_output();
set_input();
PORTB &= ~(1 << RST0_PORT); // Set pin low (common ground pin for pi reset)
PORTB &= ~(1 << RST1_PORT); // Set pin low (initialize for no pi reset)
//Configure and enable interrupts
set_interrupts();
while (1) {
sei();
start = clock();
run_timer(start);
}
return (0);
}
void run_timer(clock_t start) {
double time_elapsed;
do {
_delay_ms(1000);
if (HEARTBEAT_RECEIVED) { //If heartbeat detected, reset timer.
HEARTBEAT_RECEIVED = false;
return;
}
time_elapsed = ( clock() - start ) / CLOCKS_PER_SECOND;
} while (time_elapsed < TIMEOUT_PERIOD);
restart_raspberry_pi(); //Timeout period has elapsed, reset the pi
}
ISR(PCINT0_vect) {
//Indicate that a heartbeat has been received
HEARTBEAT_RECEIVED = true;
}
void restart_raspberry_pi() {
cli();
PORTB |= (1 << RST1_PORT); // Set pin high (sets RUN high to reset)
_delay_ms(500);
PORTB &= ~(1 << RST1_PORT); // Set pin low (release reset control)
}
void set_output()
{
//The DDxn bit in the DDRx Register selects the direction of this pin.
//If DDxn is written logic one, Pxn is configured as an output pin.
//If DDxn is written logic zero, Pxn is configured as an input pin.
//PORTB = (0<<PB0) | (1<<PB3);
DDRB = (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1); // Set pins as output.
}
void set_input()
{
DDRB |= (0<<DDB0); // set pin 0 as input. Added |=.
}
void set_interrupts()
{
GIMSK |= (1 << PCIE); // pin change interrupt enable
PCMSK |= (1 << PCINT0); // pin change interrupt enabled for PCINT0
}
#Shawn had it right....I dove into the time.h library code available to me and apparently:
Section 7.23.2.1 clock()
The type clock_t, the macro CLOCKS_PER_SEC, and the function clock() are not implemented. We
consider these items belong to operating system code, or to application code when no operating
system is present.
So I guess that's a lesson for me. Thanks for the help.

Atmel ASF SAM4E UART0 Firing Erratically

I'm attempting to set up UART communication with a GPS module but keep running into some communication error. The GPS sends a packet approximately once a second to the SAM4E16E micro, which should be trigger an interrupt and read in the data. I have two UARTS which are configured like this
conf_uart.h
#include "asf.h" //uart.h etc. included here
#define UART_SERIAL_BAUDRATE 4800
#define UART_SERIAL_CHANNEL_MODE UART_MR_CHMODE_NORMAL
#define UART_SERIAL_MODE UART_MR_PAR_NO
#define UART_SERIAL_STOP_BIT US_MR_NBSTOP_1_BIT
/* =============== UART0 =============== */
#define PINS_UART0 (PIO_PA9A_URXD0 | PIO_PA10A_UTXD0)
#define PINS_UART0_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define PINS_UART0_MASK (PIO_PA9A_URXD0 | PIO_PA9A_URXD0)
#define PINS_UART0_PIO PIOA
#define PINS_UART0_ID ID_PIOA
#define PINS_UART0_TYPE PIO_PERIPH_A
#define PINS_UART0_ATTR PIO_DEFAULT
/* =============== UART1 =============== */
#define PINS_UART1 (PIO_PB2A_URXD1 | PIO_PB3A_UTXD1)
#define PINS_UART1_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
#define PINS_UART1_MASK (PIO_PB2A_URXD1 | PIO_PB3A_UTXD1)
#define PINS_UART1_PIO PIOB
#define PINS_UART1_ID ID_PIOB
#define PINS_UART1_TYPE PIO_PERIPH_A
#define PINS_UART1_ATTR PIO_DEFAULT
conf_uart.c
#include "conf_uart.h"
void uart_custom_init_1(void) {
// set the pins to use the uart peripheral
pio_configure(PINS_UART1_PIO, PINS_UART1_TYPE, PINS_UART1_MASK, PINS_UART1_ATTR);
//enable the uart peripherial clock
pmc_enable_periph_clk(ID_UART1);
const sam_uart_opt_t uart1_settings =
{ sysclk_get_cpu_hz(), UART_SERIAL_BAUDRATE, UART_SERIAL_MODE };
uart_init(UART1,&uart1_settings); //Init UART1 and enable Rx and Tx
uart_enable_interrupt(UART1,UART_IER_RXRDY); //Interrupt reading ready
NVIC_EnableIRQ(UART1_IRQn);
}
uart_custom_init_0(void)
{
// 1. Enable UART peripheral clock
//2. Enable the required PIO's
pio_configure(PINS_UART0_PIO, PINS_UART0_TYPE, PINS_UART0_MASK, PINS_UART0_ATTR);
pmc_enable_periph_clk(ID_UART0);
// 3. call init
const sam_uart_opt_t uart0_settings =
{ sysclk_get_cpu_hz(), UART_SERIAL_BAUDRATE, UART_SERIAL_MODE };
uart_init(UART0,&uart0_settings); //Init UART1 and enable Rx and Tx
// read on interrupt
uart_enable_interrupt(UART0,UART_IER_RXRDY); //Interrupt reading ready
NVIC_EnableIRQ(UART0_IRQn);
}
void UART1_Handler() {
uint32_t dw_status = uart_get_status(UART1);
if(dw_status & UART_SR_RXRDY) {
uint8_t received_byte1;
uart_read(UART1, &received_byte);
read_buffer[read_buffer_index] = received_byte;
read_buffer_index++;
}
}
void UART0_Handler() {
uint32_t dw_status = uart_get_status(UART0);
if(dw_status & UART_SR_RXRDY)
{
uint8_t received_byte0;
uart_read(UART0, &received_byte);
read_buffer[read_buffer_index] = received_byte;
read_buffer_index++;
}
}
UART1 works perfectly. UART0 Only fires roughly once per packet, and is not even getting the first byte in the packet (should be 36, receives 16). As far as I can tell they are identical. The chip is working, I can see it transmitting on the scope. I'm basically fresh out of ideas.

AVR GCC, Generating tone with Timer0 does not work

I'm trying to convert an old ASM programme to C.
I'm quite sure I extracted all the logic needed, but it simply doesn't work.
My goal is to use a timer compare match to toggle output pin, generating a buzz for speaker.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
// speaker pin
#define SPK _BV(PA0)
#define SYSPORT PORTA
#define SYSPIN PINA
#define SYSDDR DDRA
ISR(TIMER1_COMPA_vect)
{
SYSPIN |= SPK; // toggle speaker
}
void main()
{
cli(); // disable all interrupts
SYSDDR = 0b00000001; // SPK to output
SYSPORT = 0b00000001; // turn off SPK
TCCR0A = _BV(WGM01); // CTC mode
TCCR0B = _BV(CS01) | _BV(CS00); // Prescaler 64
OCR0A = 62; // compare match = 62 (output freq 1kHz)
TIMSK = _BV(OCIE0A); // enable timer interrupt
sei(); // enable all interrupts
while(1) {} // infinite loop.
}
This code does not make a single beep, not even clicking, nothing at all.
However, when I just use a loop and delay, it works beautifylly - proving the speaker is connected properly.
I cannot do this though, I have to do something else while it is making the sound.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <stdint.h>
// speaker pin
#define SPK _BV(PA0)
// PORTA
#define SYSPORT PORTA
#define SYSPIN PINA
#define SYSDDR DDRA
void main()
{
SYSDDR = 0b00000001; // SPK to output
SYSPORT = 0b00000001; // turn off SPK
while(1) {
_delay_us(100);
SYSPIN |= SPK;
}
}
Fuses are set to
LFUSE = 0xE2
HFUSE = 0xDF
Frequency 4MHz.
Oh lol, I'm so inattentive
This should have been
ISR(TIMER0_COMPA_vect)
instead of
ISR(TIMER1_COMPA_vect)
It was handling a different timer :D

I2C interface on Tiva

On a Tiva (Texas Instruments Cortex M4F ARM) TM4C129XNCZAD I have a problem with I2C interface. I have enabled both a master on I2C module 4 thru port K and a slave on I2C module 6 thru port B. I have interconnected both I2C modules. Using Texas Instruments driver library I tried to send 1 byte using I2C_MASTER_CMD_SINGLE_SEND command. I spend a lot of time to make it working, but SCK line keeps Low logical level. I followed exactly TivaWare™ Peripheral Driver Library USER’S GUIDE, but the communication doesn't work. Has anybody some experience with it?
There is my code:
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "inc/tm4c129xnczad.h"
#define SLAVE_ADDRESS 0x3C
void delay (void)
{
volatile uint32_t ui32Loop;
for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++);
}
volatile uint32_t result;
int main (void)
{
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3 | SYSCTL_RCGCGPIO_R9 | SYSCTL_RCGCGPIO_R1;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
result = SYSCTL_RCGCGPIO_R;
//
// Enable the GPIO pin for the LED (PD3). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTD_AHB_DIR_R = 0x8;
GPIO_PORTD_AHB_DEN_R = 0x8;
GPIO_PORTK_DEN_R = 0xC0; // Enable Port K for I2C module 4
GPIO_PORTB_AHB_DEN_R = 0xC0; // Enable Port B for I2C module 6
SYSCTL_RCGCI2C_R = (1 << 4) | (1 << 6); // Mode Clock Gating Control for I2C modules 4 and 6
GPIO_PORTK_AFSEL_R = 0xC0; // Alternate Function Select PK6, PK7
GPIO_PORTB_AHB_AFSEL_R = 0xC0; // Alternate Function Select PB6, PB7
GPIOPinConfigure(GPIO_PK6_I2C4SCL);
GPIOPinConfigure(GPIO_PK7_I2C4SDA);
GPIOPinConfigure(GPIO_PB6_I2C6SCL);
GPIOPinConfigure(GPIO_PB7_I2C6SDA);
GPIOPinTypeI2C(GPIO_PORTK_BASE, 7); // Configurtes SDA
GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, 6); // Configurtes SCL
GPIOPinTypeI2C(GPIO_PORTB_BASE, 7); // Configurtes SDA
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, 6); // Configurtes SCL
I2CMasterInitExpClk(I2C4_BASE, SysCtlClockGet(), false);
I2CSlaveEnable(I2C6_BASE);
I2CSlaveInit(I2C6_BASE, SLAVE_ADDRESS);
I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
//
// Loop forever.
//
while(1)
{
//
// Turn on the LED.
//
GPIO_PORTD_AHB_DATA_R |= 0x8;
I2CMasterDataPut(I2C4_BASE, 0x33);
I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_SEND);
//
// Wait until the slave has received and acknowledged the data.
//
while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));
//
// Read the data from the slave.
//
result = I2CSlaveDataGet(I2C6_BASE);
//
// Wait until master module is done transferring.
//
while(I2CMasterBusy(I2C4_BASE));
//
// Delay for a bit.
//
delay ();
//
// Turn off the LED.
//
GPIO_PORTD_AHB_DATA_R &= ~(0x8);
//
// Delay for a bit.
//
delay ();
}
}
The problem has been resolved. There were issues:
It is essential to populate external pull ups.
Use GPIOPinTypeI2C() 2nd parameter as a bit field instead of a bit number.
The procedure SysCtlClockSet() is dedicated specially to TM4C123 devices. Instead use g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000);
For a Master clock setting do not use SysCtlClockGet() procedure. This is also dedicated to TM4C123 devices. Instead use I2CMasterInitExpClk(I2C4_BASE, g_ui32SysClock, false);
Here is the updated code,
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "inc/tm4c129xnczad.h"
#define SLAVE_ADDRESS 0x3C
void delay (void)
{
volatile uint32_t ui32Loop;
for(ui32Loop = 0; ui32Loop < 200; ui32Loop++);
}
volatile uint32_t result;
uint32_t g_ui32SysClock;
int main(void)
{
g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_XTAL_25MHZ | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000);
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3 | SYSCTL_RCGCGPIO_R9 | SYSCTL_RCGCGPIO_R1;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
result = SYSCTL_RCGCGPIO_R;
//
// Enable the GPIO pin for the LED (PD3). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTD_AHB_DIR_R = 0x8;
GPIO_PORTD_AHB_DEN_R = 0x8;
SYSCTL_RCGCI2C_R = (1 << 4) | (1 << 6); // Mode Clock Gating Control for I2C modules 4 and 6
GPIOPinConfigure(GPIO_PK6_I2C4SCL);
GPIOPinConfigure(GPIO_PK7_I2C4SDA);
GPIOPinConfigure(GPIO_PB6_I2C6SCL);
GPIOPinConfigure(GPIO_PB7_I2C6SDA);
GPIOPinTypeI2C(GPIO_PORTK_BASE, (1 << 7)); // Configures SDA
GPIOPinTypeI2CSCL(GPIO_PORTK_BASE, (1 << 6)); // Configures SCL
GPIOPinTypeI2C(GPIO_PORTB_BASE, (1 << 7)); // Configures SDA
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, (1 << 6)); // Configures SCL
I2CMasterInitExpClk(I2C4_BASE, g_ui32SysClock, false);
I2CSlaveEnable(I2C6_BASE);
I2CSlaveInit(I2C6_BASE, SLAVE_ADDRESS);
I2CMasterSlaveAddrSet(I2C4_BASE, SLAVE_ADDRESS, false);
//
// Loop forever.
//
while(1)
{
//
// Turn on the LED.
//
GPIO_PORTD_AHB_DATA_R |= 0x8;
I2CMasterDataPut(I2C4_BASE, 0x33);
I2CMasterControl(I2C4_BASE, I2C_MASTER_CMD_SINGLE_SEND);
//
// Wait until the slave has received and acknowledged the data.
//
while(!(I2CSlaveStatus(I2C6_BASE) & I2C_SLAVE_ACT_RREQ));
//
// Read the data from the slave.
//
result = I2CSlaveDataGet(I2C6_BASE);
//
// Wait until master module is done transferring.
//
while(I2CMasterBusy(I2C4_BASE));
//
// Delay for a bit.
//
delay ();
//
// Turn off the LED.
//
GPIO_PORTD_AHB_DATA_R &= ~(0x8);
//
// Delay for a bit.
//
delay ();
}
}
I was able to get I2C working on TIVA Launchpad TM4C123GH6PM. I used the the Tivaware library. I created 3 functions, init and write. Here are the functions.
Initialization
void initI2C0(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
//reset I2C module
SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
//enable GPIO peripheral that contains I2C
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
// Configure the pin muxing for I2C0 functions on port B2 and B3.
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
// Select the I2C function for these pins.
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
// Enable and initialize the I2C0 master module. Use the system clock for
// the I2C0 module. The last parameter sets the I2C data transfer rate.
// If false the data rate is set to 100kbps and if true the data rate will
// be set to 400kbps.
I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
//clear I2C FIFOs
HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;
}
I2C Write Function
void writeI2C0(uint16_t device_address, uint16_t device_register, uint8_t device_data)
{
//specify that we want to communicate to device address with an intended write to bus
I2CMasterSlaveAddrSet(I2C0_BASE, device_address, false);
//register to be read
I2CMasterDataPut(I2C0_BASE, device_register);
//send control byte and register address byte to slave device
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
//wait for MCU to finish transaction
while(I2CMasterBusy(I2C0_BASE));
I2CMasterSlaveAddrSet(I2C0_BASE, device_address, true);
//specify data to be written to the above mentioned device_register
I2CMasterDataPut(I2C0_BASE, device_data);
//wait while checking for MCU to complete the transaction
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
//wait for MCU & device to complete transaction
while(I2CMasterBusy(I2C0_BASE));
}
Complete code for TIVA + I2C can be found here.
Reference
I2C Communication with the TI Tiva TM4C123GXL

Resources