I have a TIVA tm4c123G I have been trying to create a communication between it and my ADXL345 sensor using I2C protocol which I succeeded in writing and reading from the accelerometer the readings of the device address and the register values that I just wrote to which means everything is running fine. However I have tried this in step by step debugging in keil and it works fine but if I run the program it will give zeroes all the way and I have no idea why? Should I add delays between the write and read from registers or whats going wrong in my code?
Here is my code attached
I am using a clock of 80 MHZ for the system and I think this might be the problem however as the code goes too fast to the execution of a next send and there should be some delay? I am not sure I'm only guessing please help thanks !
also my connection for the adxl is
Vcc -> 3.3 volts
GND -> ground
CS -> 3.3 volts
SDO -> ground
SDA -> PB3
SCL -> PB2
#include "tm4c123gh6pm.h"
#include "stdint.h"
void EnableI2CModule0(void);
uint8_t ReadRegister(uint8_t RegisterAddress);
void PLL_Init(void);
void WriteRegister(uint8_t RegisterAddress,uint8_t Data);
volatile uint8_t X_Axis1,X_Axis2,Y_Axis1,Y_Axis2,Z_Axis1,Z_Axis2=0;
int main()
{
volatile long temp;
PLL_Init();
EnableI2CModule0();
temp=ReadRegister(0x00);
WriteRegister(0x2D,0x08);
temp=ReadRegister(0x2D);
WriteRegister(0x31,0x0B);
temp=ReadRegister(0x31);
while(1)
{
X_Axis1=ReadRegister(0x32);
X_Axis2=ReadRegister(0x33);
Y_Axis1=ReadRegister(0x34);
Y_Axis2=ReadRegister(0x35);
Z_Axis1=ReadRegister(0x36);
Z_Axis2=ReadRegister(0x37);
}
}
void PLL_Init(void){
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
void EnableI2CModule0(void)
{
volatile int Delay=0;
SYSCTL_RCGCI2C_R|=0x00000001; //set i2c module 0 clock active
Delay=SYSCTL_RCGCI2C_R; //delay allow clock to stabilize
SYSCTL_RCGCGPIO_R |=0x00000002; //i2c module 0 is portB so activate clock for port B
Delay = SYSCTL_RCGCGPIO_R; //delay allow clock to stabilize
GPIO_PORTB_AFSEL_R|= 0x0000000C; //enable alternate functions for PB2 and PB3
GPIO_PORTB_ODR_R |= 0x00000008; //set PB3 (I2C SDA) for open drain
GPIO_PORTB_DEN_R |= 0xFF; //Enable digital on Port B
GPIO_PORTB_PCTL_R |=0x03;
I2C0_PP_R |= 0x01;
I2C0_MTPR_R |= 0x00000027; //set SCL clock
I2C0_MCR_R |= 0x00000010; //intialize mcr rigester with that value given in datasheet
}
uint8_t ReadRegister(uint8_t RegisterAddress)
{
volatile uint8_t result=0;
I2C0_MSA_R = 0x000000A6; //write operation
I2C0_MDR_R = RegisterAddress; //place data to send mdr register
I2C0_MCS_R = 0x00000007; //stop start run
while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit
I2C0_MSA_R = 0x000000A7; // read operation
I2C0_MCS_R = 0x00000007; // stop start run
while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit
result = I2C0_MDR_R;
return result;
}
void WriteRegister(uint8_t RegisterAddress,uint8_t Data)
{
I2C0_MSA_R = 0x000000A6; //write operation
I2C0_MDR_R = RegisterAddress; //place register address to set in mdr register
I2C0_MCS_R = 0x00000003; //burst send ( multiple bytes send )
while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit
I2C0_MDR_R = Data; //place data to be sent in mdr register
I2C0_MCS_R = 0x00000005; // transmit followed by stop state
while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit
}
Your WriteRegister and ReadRegister functions do not follow the flowcharts defined in the TM4C123G data sheet. Apart from not checking or handling the MCS ERROR flag, Figure 16-10 Master TRANSMIT of Multiple Data Bytes shows that when writing the MCS register, you should assert specific bits, while you are writing to all bits, You should instead perform a read-modify-write:
I2C0_MCS_R = 0x00000003; //burst send ( multiple bytes send )
should be:
// I2CMCS = ---0-011
uint32_t mcs = I2C0_MCS_R ;
msc &= ~0x00000014; // ---0-0--
mcs |= 0x00000003; // ------11
I2C0_MCS_R = mcs ;
And similarly:
I2C0_MCS_R = 0x00000005; // transmit followed by stop state
should be
// I2CMCS = ---0-101
mcs = I2C0_MCS_R ;
mcs &= ~0x00000012; // ---0--0-
mcs |= 0x00000005; // -----1-1
I2C0_MCS_R = mcs ;
ReadRegister() has a similar issue (although it is unlikely to be an issue in this case):
I2C0_MCS_R = 0x00000007; //stop start run
should strictly be:
// I2CMCS = ---00111
uint32_t mcs = I2C0_MCS_R ;
mcs &= ~0x00000018; // ---00---
mcs |= 0x00000007; // -----111
I2C0_MCS_R = mcs ;
The datasheet recommends for bits 31:5:
Software should not rely on the value of a reserved bit. To provide
compatibility with future products, the value of a reserved bit should
be preserved across a read-modify-write operation.
The above code does that, but in practice should not be necessary on this specific product, but is good practice in any case.
In any event you should add the recommended error handling code. It may be that no error flag is being set, but we don't know that unless you check for it, and doing so will at least assist debugging - rather then stepping the code, you can simply set a break-point on the error handling and then run at full-speed. This will narrow down the number of possibilities.
as #Clifford had explained that i should follow the flow charts and although his answer is completely correct it didn't give me any results (previously gave values in case of stepping into the function gave zeroes afterwards) but , i noticed something in the flow charts that i hadn't noticed before which contradicts with the initialization and configuration section in the data sheet
now as it says in step 11 that you should be polling the bus busy bit in the MCS register but this is wrong and contradicts with the flow charts , the flow charts are more correct as u should check if the bus is busy before sending anything and then check for the master busy bit before reading from the MDR register or moving on to execute and further steps
basically the correct steps in the initialization and configuration should be :
before step 10 poll the bus busy bit in case any other master is sending which can be omitted in case of a single master
after step 10 poll the busy bit before reading or going to any further step to conclude whether the sending has been completed and the master is idle or not
i'm sorry i feel like a complete idiot now for not reading the flow charts carefully but i followed another part which is the initialization and configuration part accepting a fact which wasn't there that both should imply the same thing .
i also found that it works correctly in the tivaware API following the flow charts and not that other section in the datasheet however i didn't want to use the Tivaware API as i am looking forward for problems like this which lead to a better understanding of how things work
thanks again for your help #Clifford cheers!
Related
I am trying to read a SDP610 sensiron differential pressure sensor via a Texas Instruments msp430.
I am having the issue of the sensor not acknowledging the command and thus, not communicating the pressure value itself. Note I have confirmed that the sensor works by hooking it up to an arduino via an opensource library and, I can see the data via this. Note my IDE is code composer. My chips is MSP430FR2311 (a launch pad breakout board).
My hardware setup is 4 wires. Vcc(3.3V), Ground(0V), SDK and SCL. The SDK and SCL lines are pulled to VCC with a 4.7Kohm resistor as per specification.
I have the following code for my MSP430 see below:
However, I do not see the response of the sensor via a logic analyser. Here is my capture. You will have to click the link. Note the top line is clock and bottom is the data.
MSP430 output.
The logic flow for reading the sensor from the datasheet and from the arduino code is as follows:
Write address of the device to the I2C line(8 bit h81)
Wait for slave acknowledge
Write command for reading (8 bit hF1)
Wait for slave acknowledge
Slave holds the master
Slave outputs 3 bytes (2 data one msb and 1 lsb then a check sum)
acknowledge
This is the datasheet for the sensor
Any tips to why the sensor is not responding.
CODE
void Read_Diff_pressure(void)
{
int rx_byte;
UCB0CTL1 |= UCTXSTT+ UCTR; // Generating START + I2C transmit (write)
UCB0I2CSA = SDP610Address; // SDP610 7 bit address 0x40
UCB0TXBUF = SDP610Read; // sending the read command 0x78
while(!(UCB0IFG & UCTXIFG)); //wait until reg address got sent
while( UCB0CTL1 & UCTXSTT); //wait till START condition is cleared
UCB0CTL1 |= UCTXSTT; //generate RE-START
UCB0I2CSA = SDP610Address; // SDP610 7 bit address 0x40
UCB0CTL1 &=~ UCTR; //receive mode
while( UCB0CTL1 & UCTXSTT); //wait till START condition is cleared
rx_byte = UCB0RXBUF; //read byte
//while(!(UCB0IFG & UCRXIFG)); //wait while the Byte is being read
UCB0CTL1 |= UCTXNACK; //generate a NACK
UCB0CTL1 |= UCTXSTP; //generate stop condition
while(UCB0CTL1 & UCTXSTP); //wait till stop condition got sent```
Pressure_result = rx_byte;
}
void InitI2C_diff(void)
{
PAOUT |= I2C_SCL_PIN|I2C_SDA_PIN;//P1.2(SDA) - P1.3(SCL) as per silk screen defined in a header
PADIR |= I2C_SCL_PIN|I2C_SDA_PIN;
PASEL0 |= (I2C_SCL_PIN|I2C_SDA_PIN); // configure I2C pins (device specific)
UCB0CTLW0 |= UCSWRST; // put eUSCI_B in reset state
UCB0CTLW0 |= UCMODE_3 | UCSYNC | UCMST; // I2C master mode, SMCL
UCB0CTL1 = UCSSEL_2 + UCSWRST; //use SMCLK + still reset
UCB0BR0 = 10; // default SMCLK 1M/10 = 100KHz
UCB0BR1 = 0; //
UCB0I2CSA = SDP610Address; //The address of the device
UCB0CTLW0 &= ~UCSWRST; // eUSCI_B in operational state
//UCB0BRW = 64; // baudrate = SMCLK / 64
}
int main(void)
{
InitI2C_diff();//Init the i2c
while (1) { // Mainloop
Read_Diff_pressure();
delay(1000);//1 Second delay before re looping
}
}
A few parts were missing compared to an old Project implementation of mine (VCNL3020 + MSP430).
For example:
set the 7-bit addressing mode, single-master environment, I2C Master, synchronous mode,..Maybe I have overlooked it
Does the sensor need itself an init?
The Init Part of the I2C only looked like this:
void I2CInit( void )
{
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7;
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // 7-bit addressing, single-master environment, I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 16; // fSCL = SMCLK/UCB0BR1
UCB0BR1 = 0;
UCB0I2CIE |= UCNACKIE; // Enable not-acknowledge interrupt
UCB0I2CSA=slave_adress;
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0TXIE + UCB0RXIE; // Enable TX&RX interrupts
}
To not make it unnecessary complicated, you could check my implementation on github and see if it helps Github Link I2C MSP430 Main
I hope this helps a bit- have fun!
I'm not sure what your hardware looks like, but your I2C pull-ups sound too large.I know of lot of app notes talk about about 4.7K, but I'd look at the rise time of the lines with an oscilloscope. If you don't have access to a scope, I'd use 1K or 2 K and see what happens.
Hello i have been coding with Tm4c123gh6pm lately and i have faced a part where i want to use the edge timing mode , now i haven't went for the tivaware api's i just went for traditional register level and following the datasheet and i faced this problem
i want to know which pin to use as the one where the timer is waiting for the rising edge to come so it moves the current timer value ?
i checked the data sheet all i can find is that timer 0 is somehow related to PB6 and PF0 now i tried PB6 and it didn't work but is that even the correct approach ?
are these the correct pins the microcontroller's timer waits for the rising edge to move the current timer value ?
here is a sample of my code and please note that this is just a testing code im trying its not a final code what i did was copy the initialization section in the datasheet for the timer mode i want and followed it step by step
this code will make the counter start running from 0xFF downwards but when i place a 'high' signal i.e 3.3 volts on PB6 nothing is moved to the GPTMTnR register.
i just wonder if there is something im doing wrong and im not noticing ?
#include "tm4c123gh6pm.h"
void Timer0Init(void);
int main(void)
{
int i=0;
Timer0Init();
while(1){
for(i=0;i<100000;i++){
}
}
return 0;
}
void Timer0Init(void)
{
//initialize PORT B
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x00000002; // 1) B clock
delay = SYSCTL_RCGC2_R; // delay to allow clock to stabilize
GPIO_PORTB_AMSEL_R &= 0x00; // 2) disable analog function
GPIO_PORTB_PCTL_R &= 0x00000000; // 3) GPIO clear bit PCTL
GPIO_PORTB_DIR_R &= 0x00; // 4.2) PB all input
GPIO_PORTB_AFSEL_R &= 0x40; // 5) no alternate function
GPIO_PORTB_DEN_R |= 0xFF; // 7) enable digital pins PF4-PF1
GPIO_PORTB_PCTL_R = 7;
//timer clock
SYSCTL_RCGCTIMER_R |=0x01;
delay = SYSCTL_RCGCTIMER_R;
//1. Ensure the timer is disabled (the TnEN bit is cleared) before making any changes.
TIMER0_CTL_R &= 0xFE;
//2. Write the GPTM Configuration (GPTMCFG) register with a value of 0x0000.0004.
TIMER0_CFG_R= 0x00000004;
//3. In the GPTM Timer Mode (GPTMTnMR) register, write the TnCMR field to 0x1 and the TnMR field to 0x3.
TIMER0_TAMR_R= TIMER0_TAMR_R | 0x007;
//4. Configure the type of event that the timer captures by writing the TnEVENT field of the GPTM Control (GPTMCTL) register.
TIMER0_CTL_R = TIMER0_CTL_R & 0xFFFFFFF3;
//5. If a prescaler is to be used, write the prescale value to the GPTM Timer n Prescale Register (GPTMTnPR).
//no prescaler for now
//6. Load the timer start value into the GPTM Timer n Interval Load (GPTMTnILR) register.
TIMER0_TAILR_R = 0xFF;
//7. If interrupts are required, set the CnEIM bit in the GPTM Interrupt Mask (GPTMIMR) register.
//no interrupts required
//8. Set the TnEN bit in the GPTM Control (GPTMCTL) register to enable the timer and start counting.
TIMER0_CTL_R= TIMER0_CTL_R & 0x00000001;
TIMER0_CTL_R |= 0x01;
//9. Poll the CnERIS bit in the GPTMRIS register or wait for the interrupt to be generated (if enabled). In both cases,
//the status flags are cleared by writing a 1 to the CnECINT bit of the GPTM Interrupt Clear (GPTMICR) register.
//The time at which the event happened can be obtained by reading the GPTM Timer n (GPTMTnR) register.
/*In Input Edge Timing mode, the timer continues running after an edge event has been detected,
but the timer interval can be changed at any time by writing the GPTMTnILR register. The change
takes effect at the next cycle after the write.*/
}
there was a problem with my portb initialization i used tivaware for that part and it worked perfectly fine now on placing high on PB6 it passes the current timer value to the other register
also note that when counting up the timer counts up to the value initialized in the TAIL_R register also if u want to reset the timer you need to write the value u want the timer to begin with in the TAV_R register
Best Of Luck everyone
i have a tiva c micro controller the tm4c123gxl and i have been trying for a while now to use the I2C module on the board with a digital accelrometer with no result , i have been trying to set the MDR register with a certain value to send but it stays as 0
here is the code i am using for intialization till reaching part where i set the MDR register im using step by step debugging i run the code initially to the assignment step of I2C3_MDR_R = 0x2D;
void PortDInit(void)
{
volatile unsigned long delay=0;
SYSCTL_RCGCI2C_R|=0x8; //1-set clock of I2C of module 3
delay = SYSCTL_RCGC2_R; //2-delay to allow clock to stabilize
SYSCTL_RCGC2_R |= 0x00000008; //3-port D clock
delay = SYSCTL_RCGC2_R; //4-delay to allow clock to stabilize
GPIO_PORTD_AFSEL_R |= 0x03; //5-alternate function set for I2C mode
GPIO_PORTD_DEN_R |=0x03; //6-enable digital functionality for PA6 and PA7
GPIO_PORTD_ODR_R|=0x02; //7-enable open drain mode for I2CSDA register of port A
GPIO_PORTD_PCTL_R = 0x00000033; //8-set PCTL to I2C mode
I2C3_MCR_R= 0x00000010; // 9-intialize the i2c master
I2C3_MTPR_R = 0x00000007; // 10-number of system clock cycles in 1 scl period
I2C3_MSA_R = 0x3A // set slave address and read write bit
I2C3_MDR_R = 0x2D; // data to be sent BREAK POINT HERE using single step here yields MDR with same value = 0
I2C3_MCS_R = 0x00000003; // follow transmit condition
while(I2C3_MCS_R &= 0x40 == 1); // wait bus is busy sending data
if(I2C3_MCS_R&=0x04 ==1)
{
//handle error in communication
}
else
{
//success in transmission
}
what i have done to reach this code
carefully understood the I2C protocol how it works etc.
check the data sheet and follow the initalization steps mentioned there step by step which got me to this code
i know i should use tivaware library which will be easier but using
the registers helps me understand more of how everything is working ,
im still a student
at first i didnt have the digital enable line as it wasnt mentioned
to be activated for the I2C but its only logical it should be there
as we are using digital values i tried with both yielded the same
output mdr=0
i am using keil 4 as my IDE and im viewing the values of registers of
I2C module 3 to know whether data is placed in MDR or not
hope any one helps
thanks.
This is a long shot, but here goes:
in your comments, step 6 says
//6-enable digital functionality for PA6 and PA7
but it appears you are working on GPIO_PORTD...
maybe its a comment typo (you meant PD6 and PD7)
but just double check you are looking at the right pins...
Good luck!
So I'm having a problem getting a TI microcontroller to communicate with the Raspberry Pi B+. The exact microcontroller I'm using is the TI cc430f5137. The issue I'm having is that I just can't seem to get the Raspberry Pi to correctly receive the data I'm sending from the MSP430. For those who don't know, the 430 has 2 buffers for this purpose, a RX and TX, which allows the use of the UART module while code is still executing. I've enabled an interrupt for when I receive a byte, and I simply set a flag and send the same byte right back. It works up until I attempt to transmit.
The code sits and waits in an infinite loop until it receives it's first byte. At that point it simply saves the byte and flashes the LED if it's a 'T' (for testing). Upon returning to the loop, it detects that the saved byte has changed, and puts it in the buffer to send it back. Until this point, everything works perfectly. It receives the correct byte every time, letting me know my clocks are perfect, my interrupt is working, and my UART initialization is correct. Where it goes wrong is after sending the byte, it seems like there is some kind of internal loopback (this is an option but I made sure this is not the case) that is causing the interrupt to re-trigger, resulting in an infinite loop of transmitting and again receiving the same byte, but upon invoking this via the Pi I don't get back a loop of the same character, but instead a byte of random garbage that has no consistency or logic behind it. I analyzed the bits to see if the timing is just off and that doesn't seem to be the case. For reference, my Baud is a measly 1200, the voltage of both devices is definitely 3.3v, and I'm sure the Pi is working because when I short the RX and TX, I get back the byte without an issue. I switched to UART because SPI was giving me similar problems, and I can't think of any other protocol besides I2C that would help here. I am using an external 32768hz crystal. Also, I've tried this on two different microcontrollers, so its definitely the code that's the issue.
#include <msp430.h>
char temp;
char in;
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
P1OUT = 0x00; // Make sure pins are tturned off
P1DIR = 0x01; // Led out
P1SEL |= BIT5 + BIT6; // UART as pin mode
UCSCTL6 &= ~BIT0; // Turn on XT1
P5SEL |= BIT0 + BIT1; // Select XT1 as pin function
UCA0CTL1 |= BIT0; // Set UART to reset mode
UCA0CTL1 |= BIT6; // Choose ACLK as source
UCA0BR0 = 27; // Set speed to 1200 Baud
UCA0MCTL = 0x02 << 1; // Set speed to 1200 Baud
UCA0CTL1 &= ~BIT0; // Turn UART on
UCA0IE = BIT0; // Enable RX interrupt
__enable_interrupt();
while(1)
{
if(in != 0)
{
UCA0TXBUF = in;
temp = in;
in = 0;
}
}
}
#pragma vector=USCI_A0_VECTOR
__interrupt void UCSIA0(void)
{
in = UCA0RXBUF;
if(in == 0x54)
P1OUT ^= BIT0;
}
Output from running minicom at 1200 on Pi, Sending 'T' one at a time:
UÔÿÿïÕuU_þýÿÿÿÿÿÿÕԯÿÿôÕüÿÝUõï\þþÿÿÕ¿ÿÿýýTÿýUÿÿÿïÿÿÿõÿýýÿõûÿ
assuming Pi is working currectly...
1.verify msp430 TX is woring: send every 1 sec known value and see if PI getting it currectly.
2.verify MSP430 RX working: send from Pi known value every 1 sec.
3.interrupt section:
your code dosent verfiy that RX interrupt is off.
you should filter interrupts generated only for the RX .
also, your code dont handle overrun/frame errors.
sharing "in" variable both for TX and RX (and both at interrupt and main loop section)-not good idea..
4.your output example suggests that you have baud rate mismatch issue.
if you send character 'T' and shoud get back 'T'. i expect to see 'TTTTTT...'
BTW this garbage may suggests that you forgot to connecting GND line between two MCUs...
The code is for an AVR atamega168xplained mini board, with an ATmega168pb MCU. The shift register I am using is a Texas Instruments TPIC6C595 I have the drain outputs of the shift register connected to the anodes of 8 LEDs. The OE(G) pin of shift register is tied to GND, and CLR tied to 5V. There is a 100nF ceramic capacitor between shift register VCC and GND. SER OUT is left unconnected to anything since I am trying to bit-bang just this one before I move up to chaining shift registers.
What happens is that I get no output from the shift register, all drain outputs are low (tested with multimeter). When I disconnect the SER IN, SRCK, and RCK from the microcontroller i get some flickering on only one of the LEDs which I guess is a result of those pins floating and being in an undefined state. I would have expected at least to get some kind of garbage output even if the code was wrong, but I get more of an output with the microcontroller completely disconnected. I know it is outputting a signal because I can connect it to the LEDS without the shift register and see they are lit up at various levels of intensity but do not have an oscilloscope to be able to actually look at the signals.
This is the code, with the defines for the output port at the top of the file included so it's clear what's being done:
#define DDR_SREG DDRD
#define PORT_SREG PORTD
#define SRCK _BV(PORTD0)
#define RCK _BV(PORTD1)
#define SER _BV(PORTD2)
void display_write(uint8_t data)
{
char i;
PORT_SREG &= ~RCK; // latch low
for (i = 0; i < 8; ++i) {
PORT_SREG &= ~SRCK; // clock low
if (data & 1) // serial out
PORT_SREG |= SER;
else
PORT_SREG &= ~SER;
PORT_SREG |= SRCK; // clock high
data >>= 1; // shift data
}
PORT_SREG |= RCK; // latch high
}
Solved it. After doing some more research, it was apparent that this shift register has open drain outputs and cannot source current (they can only sink current). Adjusting the wiring accordingly I was able to get the shift register working to my satisfaction.