Commit 4cb937ab authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'restyle' into proposed2

parents a2721762 e625cbd9
# choose your board here.
# choose your board here.
BOARD = spec
# 1 enables Etherbone support
......@@ -81,8 +81,8 @@ OBJS_PTPD = $(PTP_NOPOSIX)/PTPWRd/arith.o \
$(PTP_NOPOSIX)/libposix/net.o \
$(PTP_NOPOSIX)/softpll/softpll_ng.o
CFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled
LDFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled -nostdlib -T arch/lm32/ram.ld
CFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled
LDFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled -nostdlib -T arch/lm32/ram.ld
OBJS_PLATFORM=arch/lm32/crt0.o arch/lm32/irq.o arch/lm32/debug.o
......@@ -96,14 +96,14 @@ CC=$(CROSS_COMPILE)gcc
OBJDUMP=$(CROSS_COMPILE)objdump
OBJCOPY=$(CROSS_COMPILE)objcopy
SIZE=$(CROSS_COMPILE)size
CFLAGS= $(CFLAGS_PLATFORM) $(CFLAGS_EB) $(CFLAGS_PTPD) $(INCLUDE_DIRS) -ffunction-sections -fdata-sections -Os -Iinclude -include include/trace.h $(PTPD_CFLAGS) -I$(PTP_NOPOSIX)/PTPWRd -I. -Isoftpll
LDFLAGS= $(LDFLAGS_PLATFORM) -ffunction-sections -fdata-sections -Wl,--gc-sections -Os -Iinclude
OBJS=$(OBJS_PLATFORM) $(OBJS_WRC) $(OBJS_PTPD) $(OBJS_SHELL) $(OBJS_TESTS) $(OBJS_LIB) $(OBJS_SOCKITOWM) $(OBJS_SOFTPLL) $(OBJS_DEV)
OUTPUT=wrc
REVISION=$(shell git rev-parse HEAD)
$(shell ln -sf ../boards/$(BOARD)/board.h include/board.h)
$(shell ln -sf ../boards/$(BOARD)/board.h include/board.h)
all: tools wrc
......@@ -112,14 +112,14 @@ wrc: $(OBJS)
echo "const char *build_date = __DATE__ \" \" __TIME__;" >> revision.c
$(CC) $(CFLAGS) -c revision.c
$(SIZE) -t $(OBJS)
${CC} -o $(OUTPUT).elf revision.o $(OBJS) $(LDFLAGS)
${CC} -o $(OUTPUT).elf revision.o $(OBJS) $(LDFLAGS)
${OBJCOPY} -O binary $(OUTPUT).elf $(OUTPUT).bin
${OBJDUMP} -d $(OUTPUT).elf > $(OUTPUT)_disasm.S
cd tools; $(MAKE)
./tools/genraminit $(OUTPUT).bin 0 > $(OUTPUT).ram
./tools/genramvhd -s 90112 $(OUTPUT).bin > $(OUTPUT).vhd
clean:
clean:
rm -f $(OBJS) $(OUTPUT).elf $(OUTPUT).bin $(OUTPUT).ram
%.o: %.c
......
......@@ -3,7 +3,7 @@
* Load this code anywhere in memory and point DEBA at it.
* When DC=1 it chain loads the exception handlers at EBA.
* User exception handlers must save to the stack.
*
*
* Copyright (C) 2011 by Wesley W. Terpstra <w.terpstra@gsi.de>
*/
......@@ -289,7 +289,7 @@ handle_debug_trap:
calli jtag_put_byte
_get_command:
/* Input: [Wxxxxxxx]
/* Input: [Wxxxxxxx]
* W=0, x=0: quit debug trap
* W=1, x=0: report register dump location
* W=0, x>0: read 'x' bytes
......@@ -306,7 +306,7 @@ _get_command:
/* Load memory access address */
calli jtag_get_word
mv r11, r1
/* Either read or write */
bne r10, r0, _read_mem
......
......@@ -2,38 +2,36 @@
void disable_irq()
{
unsigned int ie, im;
unsigned int Mask = ~1;
unsigned int ie, im;
unsigned int Mask = ~1;
/* disable peripheral interrupts in case they were enabled */
asm volatile ("rcsr %0,ie":"=r"(ie));
ie &= (~0x1);
asm volatile ("wcsr ie, %0"::"r"(ie));
/* disable peripheral interrupts in case they were enabled */
asm volatile ("rcsr %0,ie":"=r" (ie));
ie &= (~0x1);
asm volatile ("wcsr ie, %0"::"r" (ie));
/* disable mask-bit in im */
asm volatile ("rcsr %0, im":"=r"(im));
im &= Mask;
asm volatile ("wcsr im, %0"::"r"(im));
/* disable mask-bit in im */
asm volatile ("rcsr %0, im":"=r" (im));
im &= Mask;
asm volatile ("wcsr im, %0"::"r" (im));
}
void enable_irq()
{
unsigned int ie, im;
unsigned int Mask = 1;
unsigned int ie, im;
unsigned int Mask = 1;
/* disable peripheral interrupts in-case they were enabled*/
asm volatile ("rcsr %0,ie":"=r"(ie));
ie &= (~0x1);
asm volatile ("wcsr ie, %0"::"r"(ie));
/* disable peripheral interrupts in-case they were enabled */
asm volatile ("rcsr %0,ie":"=r" (ie));
ie &= (~0x1);
asm volatile ("wcsr ie, %0"::"r" (ie));
/* enable mask-bit in im */
asm volatile ("rcsr %0, im":"=r"(im));
im |= Mask;
asm volatile ("wcsr im, %0"::"r"(im));
/* enable mask-bit in im */
asm volatile ("rcsr %0, im":"=r" (im));
im |= Mask;
asm volatile ("wcsr im, %0"::"r" (im));
ie |= 0x1;
asm volatile ("wcsr ie, %0"::"r"(ie));
ie |= 0x1;
asm volatile ("wcsr ie, %0"::"r" (ie));
}
......@@ -38,7 +38,7 @@ SECTIONS
{
.boot : { *(.boot) } > ram
/* Code */
.text :
{
......@@ -60,26 +60,26 @@ SECTIONS
KEEP (*(.dtors))
KEEP (*(.jcr))
_etext = .;
} > ram =0
} > ram =0
/* Exception handlers */
.eh_frame_hdr : { *(.eh_frame_hdr) } > ram
.eh_frame : { KEEP (*(.eh_frame)) } > ram
.gcc_except_table : { *(.gcc_except_table) *(.gcc_except_table.*) } > ram
/* Read-only data */
.rodata :
{
.rodata :
{
. = ALIGN(4);
_frodata = .;
_frodata_rom = LOADADDR(.rodata);
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
_erodata = .;
} > ram
/* Data */
.data :
.data :
{
. = ALIGN(4);
_fdata = .;
......@@ -90,8 +90,8 @@ SECTIONS
_gp = ALIGN(16) + 0x7ff0;
*(.sdata .sdata.* .gnu.linkonce.s.*)
_edata = .;
} > ram
} > ram
/* BSS */
.bss :
{
......@@ -108,10 +108,10 @@ SECTIONS
_end = .;
PROVIDE (end = .);
} > ram
/* First location in stack is highest address in RAM */
PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
......@@ -120,7 +120,7 @@ SECTIONS
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
......
......@@ -10,4 +10,4 @@ int board_init()
int board_update()
{
}
\ No newline at end of file
}
......@@ -10,4 +10,4 @@ int board_init()
int board_update()
{
}
\ No newline at end of file
}
......@@ -6,45 +6,45 @@
#define DNA_SHIFT 3
#define DNA_READ 2
void dna_read(uint32_t *lo, uint32_t *hi)
void dna_read(uint32_t * lo, uint32_t * hi)
{
uint64_t dna = 0;
int i;
gpio_out(DNA_DATA, 0);
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
gpio_out(DNA_READ, 1);
delay(10);
gpio_out(DNA_SHIFT, 0);
delay(10);
delay(10);
gpio_out(DNA_CLK, 1);
delay(10);
if(gpio_in(DNA_DATA)) dna |= 1;
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
gpio_out(DNA_READ, 0);
gpio_out(DNA_SHIFT, 1);
delay(10);
uint64_t dna = 0;
int i;
gpio_out(DNA_DATA, 0);
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
gpio_out(DNA_READ, 1);
delay(10);
gpio_out(DNA_SHIFT, 0);
delay(10);
delay(10);
gpio_out(DNA_CLK, 1);
delay(10);
if (gpio_in(DNA_DATA))
dna |= 1;
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
gpio_out(DNA_READ, 0);
gpio_out(DNA_SHIFT, 1);
delay(10);
for (i = 0; i < 57; i++) {
dna <<= 1;
delay(10);
delay(10);
gpio_out(DNA_CLK, 1);
delay(10);
if (gpio_in(DNA_DATA))
dna |= 1;
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
}
for(i=0;i<57;i++)
{
dna <<= 1;
delay(10);
delay(10);
gpio_out(DNA_CLK, 1);
delay(10);
if(gpio_in(DNA_DATA)) dna |= 1;
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
}
*hi = (uint32_t) (dna >> 32);
*lo = (uint32_t) dna;
}
This diff is collapsed.
/*
WR Endpoint (WR-compatible Ethernet MAC driver
WR Endpoint (WR-compatible Ethernet MAC driver
Tomasz Wlostowski/CERN 2011
......@@ -18,7 +18,6 @@ LGPL 2.1
#include <hw/endpoint_regs.h>
#include <hw/endpoint_mdio.h>
/* Length of a single bit on the gigabit serial link in picoseconds. Used for calculating deltaRx/deltaTx
from the serdes bitslip value */
#define PICOS_PER_SERIAL_BIT 800
......@@ -33,150 +32,150 @@ volatile struct EP_WB *EP;
/* functions for accessing PCS (MDIO) registers */
uint16_t pcs_read(int location)
{
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2);
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0);
return EP_MDIO_ASR_RDATA_R(EP->MDIO_ASR) & 0xffff;
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2);
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0) ;
return EP_MDIO_ASR_RDATA_R(EP->MDIO_ASR) & 0xffff;
}
void pcs_write(int location, int value)
{
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2)
| EP_MDIO_CR_DATA_W(value)
| EP_MDIO_CR_RW;
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2)
| EP_MDIO_CR_DATA_W(value)
| EP_MDIO_CR_RW;
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0);
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0) ;
}
/* MAC address setting */
void set_mac_addr(uint8_t dev_addr[])
{
EP->MACL = ((uint32_t)dev_addr[2] << 24)
| ((uint32_t)dev_addr[3] << 16)
| ((uint32_t)dev_addr[4] << 8)
| ((uint32_t)dev_addr[5]);
EP->MACL = ((uint32_t) dev_addr[2] << 24)
| ((uint32_t) dev_addr[3] << 16)
| ((uint32_t) dev_addr[4] << 8)
| ((uint32_t) dev_addr[5]);
EP->MACH = ((uint32_t)dev_addr[0] << 8)
| ((uint32_t)dev_addr[1]);
EP->MACH = ((uint32_t) dev_addr[0] << 8)
| ((uint32_t) dev_addr[1]);
}
void get_mac_addr(uint8_t dev_addr[])
{
dev_addr[5] = (EP->MACL & 0x000000ff);
dev_addr[4] = (EP->MACL & 0x0000ff00) >> 8;
dev_addr[3] = (EP->MACL & 0x00ff0000) >> 16;
dev_addr[2] = (EP->MACL & 0xff000000) >> 24;
dev_addr[1] = (EP->MACH & 0x000000ff);
dev_addr[0] = (EP->MACH & 0x0000ff00) >> 8;
dev_addr[5] = (EP->MACL & 0x000000ff);
dev_addr[4] = (EP->MACL & 0x0000ff00) >> 8;
dev_addr[3] = (EP->MACL & 0x00ff0000) >> 16;
dev_addr[2] = (EP->MACL & 0xff000000) >> 24;
dev_addr[1] = (EP->MACH & 0x000000ff);
dev_addr[0] = (EP->MACH & 0x0000ff00) >> 8;
}
/* Initializes the endpoint and sets its local MAC address */
void ep_init(uint8_t mac_addr[])
{
EP = (volatile struct EP_WB *) BASE_EP;
set_mac_addr(mac_addr);
EP = (volatile struct EP_WB *)BASE_EP;
set_mac_addr(mac_addr);
*(unsigned int *)(0x62000) = 0x2; // reset network stuff (cleanup required!)
*(unsigned int *)(0x62000) = 0;
*(unsigned int *)(0x62000) = 0x2; // reset network stuff (cleanup required!)
*(unsigned int *)(0x62000) = 0;
EP->ECR = 0; /* disable Endpoint */
EP->VCR0 = EP_VCR0_QMODE_W(3); /* disable VLAN unit - not used by WRPC */
EP->RFCR = EP_RFCR_MRU_W(1518); /* Set the max RX packet size */
EP->TSCR = EP_TSCR_EN_TXTS | EP_TSCR_EN_RXTS; /* Enable timestamping */
EP->ECR = 0; /* disable Endpoint */
EP->VCR0 = EP_VCR0_QMODE_W(3); /* disable VLAN unit - not used by WRPC */
EP->RFCR = EP_RFCR_MRU_W(1518); /* Set the max RX packet size */
EP->TSCR = EP_TSCR_EN_TXTS | EP_TSCR_EN_RXTS; /* Enable timestamping */
/* Configure DMTD phase tracking */
EP->DMCR = EP_DMCR_EN | EP_DMCR_N_AVG_W(DMTD_AVG_SAMPLES);
EP->DMCR = EP_DMCR_EN | EP_DMCR_N_AVG_W(DMTD_AVG_SAMPLES);
}
/* Enables/disables transmission and reception. When autoneg is set to 1,
starts up 802.3 autonegotiation process */
int ep_enable(int enabled, int autoneg)
{
uint16_t mcr;
uint16_t mcr;
if(!enabled)
{
EP->ECR = 0;
return 0;
}
if (!enabled) {
EP->ECR = 0;
return 0;
}
/* Disable the endpoint */
EP->ECR = 0;
EP->ECR = 0;
mprintf("ID: %x\n", EP->IDCODE);
mprintf("ID: %x\n", EP->IDCODE);
/* Load default packet classifier rules - see ep_pfilter.c for details */
pfilter_init_default();
pfilter_init_default();
/* Enable TX/RX paths, reset RMON counters */
EP->ECR = EP_ECR_TX_EN | EP_ECR_RX_EN | EP_ECR_RST_CNT;
EP->ECR = EP_ECR_TX_EN | EP_ECR_RX_EN | EP_ECR_RST_CNT;
autoneg_enabled = autoneg;
autoneg_enabled = autoneg;
/* Reset the GTP Transceiver - it's important to do the GTP phase alignment every time
we start up the software, otherwise the calibration RX/TX deltas may not be correct */
pcs_write(MDIO_REG_MCR, MDIO_MCR_PDOWN); /* reset the PHY */
timer_delay(200);
pcs_write(MDIO_REG_MCR, MDIO_MCR_RESET); /* reset the PHY */
pcs_write(MDIO_REG_MCR, 0); /* reset the PHY */
pcs_write(MDIO_REG_MCR, MDIO_MCR_PDOWN); /* reset the PHY */
timer_delay(200);
pcs_write(MDIO_REG_MCR, MDIO_MCR_RESET); /* reset the PHY */
pcs_write(MDIO_REG_MCR, 0); /* reset the PHY */
/* Don't advertise anything - we don't want flow control */
pcs_write(MDIO_REG_ADVERTISE, 0);
pcs_write(MDIO_REG_ADVERTISE, 0);
mcr = MDIO_MCR_SPEED1000_MASK | MDIO_MCR_FULLDPLX_MASK;
if(autoneg)
mcr |= MDIO_MCR_ANENABLE | MDIO_MCR_ANRESTART;
mcr = MDIO_MCR_SPEED1000_MASK | MDIO_MCR_FULLDPLX_MASK;
if (autoneg)
mcr |= MDIO_MCR_ANENABLE | MDIO_MCR_ANRESTART;
pcs_write(MDIO_REG_MCR, mcr);
return 0;
pcs_write(MDIO_REG_MCR, mcr);
return 0;
}
/* Checks the link status. If the link is up, returns non-zero
and stores the Link Partner Ability (LPA) autonegotiation register at *lpa */
int ep_link_up(uint16_t *lpa)
int ep_link_up(uint16_t * lpa)
{
uint16_t flags = MDIO_MSR_LSTATUS;
volatile uint16_t msr;
uint16_t flags = MDIO_MSR_LSTATUS;
volatile uint16_t msr;
if(autoneg_enabled)
flags |= MDIO_MSR_ANEGCOMPLETE;
if (autoneg_enabled)
flags |= MDIO_MSR_ANEGCOMPLETE;
msr = pcs_read(MDIO_REG_MSR);
msr = pcs_read(MDIO_REG_MSR); /* Read this flag twice to make sure the status is updated */
msr = pcs_read(MDIO_REG_MSR);
msr = pcs_read(MDIO_REG_MSR); /* Read this flag twice to make sure the status is updated */
if(lpa) *lpa = pcs_read(MDIO_REG_LPA);
if (lpa)
*lpa = pcs_read(MDIO_REG_LPA);
return (msr & flags) == flags ? 1 : 0;
return (msr & flags) == flags ? 1 : 0;
}
/* Returns the TX/RX latencies. They are valid only when the link is up. */
int ep_get_deltas(uint32_t *delta_tx, uint32_t *delta_rx)
int ep_get_deltas(uint32_t * delta_tx, uint32_t * delta_rx)
{
/* fixme: these values should be stored in calibration block in the EEPROM on the FMC. Also, the TX/RX delays of a particular SFP
should be added here */
*delta_tx = sfp_deltaTx;
*delta_rx = sfp_deltaRx + PICOS_PER_SERIAL_BIT * MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
/* fixme: these values should be stored in calibration block in the EEPROM on the FMC. Also, the TX/RX delays of a particular SFP
should be added here */
*delta_tx = sfp_deltaTx;
*delta_rx =
sfp_deltaRx +
PICOS_PER_SERIAL_BIT *
MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
return 0;
}
int ep_cal_pattern_enable()
{
uint32_t val;
val = pcs_read(MDIO_REG_WR_SPEC);
val |= MDIO_WR_SPEC_TX_CAL;
pcs_write(MDIO_REG_WR_SPEC, val);
uint32_t val;
val = pcs_read(MDIO_REG_WR_SPEC);
val |= MDIO_WR_SPEC_TX_CAL;
pcs_write(MDIO_REG_WR_SPEC, val);
return 0;
return 0;
}
int ep_cal_pattern_disable()
{
uint32_t val;
val = pcs_read(MDIO_REG_WR_SPEC);
val &= (~MDIO_WR_SPEC_TX_CAL);
pcs_write(MDIO_REG_WR_SPEC, val);
uint32_t val;
val = pcs_read(MDIO_REG_WR_SPEC);
val &= (~MDIO_WR_SPEC_TX_CAL);
pcs_write(MDIO_REG_WR_SPEC, val);
return 0;
return 0;
}
This diff is collapsed.
......@@ -6,8 +6,9 @@
void mi2c_delay()
{
int i;
for(i=0;i<I2C_DELAY;i++) asm volatile ("nop");
int i;
for (i = 0; i < I2C_DELAY; i++)
asm volatile ("nop");
}
#define M_SDA_OUT(i, x) { gpio_out(i2c_if[i].sda, x); mi2c_delay(); }
......@@ -16,109 +17,105 @@ void mi2c_delay()
void mi2c_start(uint8_t i2cif)
{
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
}
void mi2c_repeat_start(uint8_t i2cif)
{
M_SDA_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
M_SDA_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
}
void mi2c_stop(uint8_t i2cif)
{
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 1);
}
unsigned char mi2c_put_byte(uint8_t i2cif, unsigned char data)
{
char i;
unsigned char ack;
char i;
unsigned char ack;
for (i=0;i<8;i++, data<<=1)
{
M_SDA_OUT(i2cif, data&0x80);
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
for (i = 0; i < 8; i++, data <<= 1) {
M_SDA_OUT(i2cif, data & 0x80);
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
M_SDA_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 1);
ack = M_SDA_IN(i2cif); /* ack: sda is pulled low ->success. */
ack = M_SDA_IN(i2cif); /* ack: sda is pulled low ->success. */
M_SCL_OUT(i2cif, 0);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
M_SDA_OUT(i2cif, 0);
return ack!=0;
return ack != 0;
}
void mi2c_get_byte(uint8_t i2cif, unsigned char *data, uint8_t last)
{
int i;
unsigned char indata = 0;
M_SDA_OUT(i2cif, 1);
/* assert: scl is low */
M_SCL_OUT(i2cif, 0);
for (i=0;i<8;i++)
{
M_SCL_OUT(i2cif, 1);
indata <<= 1;
if ( M_SDA_IN(i2cif) ) indata |= 0x01;
M_SCL_OUT(i2cif, 0);
}
if(last)
{
M_SDA_OUT(i2cif, 1); //noack
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
else
{
M_SDA_OUT(i2cif, 0); //ack
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
*data= indata;
int i;
unsigned char indata = 0;
M_SDA_OUT(i2cif, 1);
/* assert: scl is low */
M_SCL_OUT(i2cif, 0);
for (i = 0; i < 8; i++) {
M_SCL_OUT(i2cif, 1);
indata <<= 1;
if (M_SDA_IN(i2cif))
indata |= 0x01;
M_SCL_OUT(i2cif, 0);
}
if (last) {
M_SDA_OUT(i2cif, 1); //noack
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
} else {
M_SDA_OUT(i2cif, 0); //ack
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
*data = indata;
}
void mi2c_init(uint8_t i2cif)
{