machine/stm32f103xx: implmentation for I2C interface
Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
		
							родитель
							
								
									fad4a735e6
								
							
						
					
					
						коммит
						b8c326d710
					
				
					 5 изменённых файлов: 481 добавлений и 8 удалений
				
			
		|  | @ -57,3 +57,9 @@ const ( | |||
| 	SPI0_MOSI_PIN = PA7 | ||||
| 	SPI0_MISO_PIN = PA6 | ||||
| ) | ||||
| 
 | ||||
| // I2C pins | ||||
| const ( | ||||
| 	SDA_PIN = PB7 | ||||
| 	SCL_PIN = PB6 | ||||
| ) | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| // +build avr nrf | ||||
| // +build avr nrf stm32f103xx | ||||
| 
 | ||||
| package machine | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ package machine | |||
| import ( | ||||
| 	"device/arm" | ||||
| 	"device/stm32" | ||||
| 	"errors" | ||||
| ) | ||||
| 
 | ||||
| const CPU_FREQUENCY = 72000000 | ||||
|  | @ -143,8 +144,8 @@ func (uart UART) Configure(config UARTConfig) { | |||
| 
 | ||||
| // SetBaudRate sets the communication speed for the UART. | ||||
| func (uart UART) SetBaudRate(br uint32) { | ||||
| 	// first divide by PCK2 prescaler (div 4) and then desired baudrate | ||||
| 	divider := CPU_FREQUENCY / 4 / br | ||||
| 	// first divide by PCLK2 prescaler (div 1) and then desired baudrate | ||||
| 	divider := CPU_FREQUENCY / br | ||||
| 	stm32.USART1.BRR = stm32.RegValue(divider) | ||||
| } | ||||
| 
 | ||||
|  | @ -290,3 +291,461 @@ func (spi SPI) setPins(sck, mosi, miso uint8) { | |||
| 	GPIO{mosi}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) | ||||
| 	GPIO{miso}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) | ||||
| } | ||||
| 
 | ||||
| // I2C on the STM32F103xx. | ||||
| type I2C struct { | ||||
| 	Bus *stm32.I2C_Type | ||||
| } | ||||
| 
 | ||||
| // There are 2 I2C interfaces on the STM32F103xx. | ||||
| // Since the first interface is named I2C1, both I2C0 and I2C1 refer to I2C1. | ||||
| // TODO: implement I2C2. | ||||
| var ( | ||||
| 	I2C1 = I2C{Bus: stm32.I2C1} | ||||
| 	I2C0 = I2C1 | ||||
| ) | ||||
| 
 | ||||
| // I2CConfig is used to store config info for I2C. | ||||
| type I2CConfig struct { | ||||
| 	Frequency uint32 | ||||
| 	SCL       uint8 | ||||
| 	SDA       uint8 | ||||
| } | ||||
| 
 | ||||
| // Configure is intended to setup the I2C interface. | ||||
| func (i2c I2C) Configure(config I2CConfig) { | ||||
| 	// Default I2C bus speed is 100 kHz. | ||||
| 	if config.Frequency == 0 { | ||||
| 		config.Frequency = TWI_FREQ_100KHZ | ||||
| 	} | ||||
| 
 | ||||
| 	// enable clock for I2C | ||||
| 	stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_I2C1EN | ||||
| 
 | ||||
| 	// I2C1 pins | ||||
| 	switch config.SDA { | ||||
| 	case PB9: | ||||
| 		config.SCL = PB8 | ||||
| 		// use alternate I2C1 pins PB8/PB9 via AFIO mapping | ||||
| 		stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN | ||||
| 		stm32.AFIO.MAPR |= stm32.AFIO_MAPR_I2C1_REMAP | ||||
| 	default: | ||||
| 		// use default I2C1 pins PB6/PB7 | ||||
| 		config.SDA = SDA_PIN | ||||
| 		config.SCL = SCL_PIN | ||||
| 	} | ||||
| 
 | ||||
| 	GPIO{config.SDA}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN}) | ||||
| 	GPIO{config.SCL}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN}) | ||||
| 
 | ||||
| 	// Disable the selected I2C peripheral to configure | ||||
| 	i2c.Bus.CR1 &^= stm32.I2C_CR1_PE | ||||
| 
 | ||||
| 	// pclk1 clock speed is main frequency divided by PCK1 prescaler (div 2) | ||||
| 	pclk1 := uint32(CPU_FREQUENCY / 2) | ||||
| 
 | ||||
| 	// set freqency range to pclk1 clock speed in Mhz. | ||||
| 	// aka setting the value 36 means to use 36MhZ clock. | ||||
| 	pclk1Mhz := pclk1 / 1000000 | ||||
| 	i2c.Bus.CR2 |= stm32.RegValue(pclk1Mhz) | ||||
| 
 | ||||
| 	switch config.Frequency { | ||||
| 	case TWI_FREQ_100KHZ: | ||||
| 		// Normal mode speed calculation | ||||
| 		ccr := pclk1 / (config.Frequency * 2) | ||||
| 		i2c.Bus.CCR = stm32.RegValue(ccr) | ||||
| 
 | ||||
| 		// duty cycle 2 | ||||
| 		i2c.Bus.CCR &^= stm32.I2C_CCR_DUTY | ||||
| 
 | ||||
| 		// frequency standard mode | ||||
| 		i2c.Bus.CCR &^= stm32.I2C_CCR_F_S | ||||
| 
 | ||||
| 		// Set Maximum Rise Time for standard mode | ||||
| 		i2c.Bus.TRISE = stm32.RegValue(pclk1Mhz) | ||||
| 
 | ||||
| 	case TWI_FREQ_400KHZ: | ||||
| 		// Fast mode speed calculation | ||||
| 		ccr := pclk1 / (config.Frequency * 3) | ||||
| 		i2c.Bus.CCR = stm32.RegValue(ccr) | ||||
| 
 | ||||
| 		// duty cycle 2 | ||||
| 		i2c.Bus.CCR &^= stm32.I2C_CCR_DUTY | ||||
| 
 | ||||
| 		// frequency fast mode | ||||
| 		i2c.Bus.CCR |= stm32.I2C_CCR_F_S | ||||
| 
 | ||||
| 		// Set Maximum Rise Time for fast mode | ||||
| 		i2c.Bus.TRISE = stm32.RegValue(((pclk1Mhz * 300) / 1000)) | ||||
| 	} | ||||
| 
 | ||||
| 	// re-enable the selected I2C peripheral | ||||
| 	i2c.Bus.CR1 |= stm32.I2C_CR1_PE | ||||
| } | ||||
| 
 | ||||
| // Tx does a single I2C transaction at the specified address. | ||||
| // It clocks out the given address, writes the bytes in w, reads back len(r) | ||||
| // bytes and stores them in r, and generates a stop condition on the bus. | ||||
| func (i2c I2C) Tx(addr uint16, w, r []byte) error { | ||||
| 	var err error | ||||
| 	if len(w) != 0 { | ||||
| 		// start transmission for writing | ||||
| 		err = i2c.signalStart() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		// send address | ||||
| 		err = i2c.sendAddress(uint8(addr), true) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		for _, b := range w { | ||||
| 			err = i2c.WriteByte(b) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// sending stop here for write | ||||
| 		err = i2c.signalStop() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if len(r) != 0 { | ||||
| 		// re-start transmission for reading | ||||
| 		err = i2c.signalStart() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		// 1 byte | ||||
| 		switch len(r) { | ||||
| 		case 1: | ||||
| 			// send address | ||||
| 			err = i2c.sendAddress(uint8(addr), false) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// Disable ACK of received data | ||||
| 			i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK | ||||
| 
 | ||||
| 			// clear timeout here | ||||
| 			timeout := i2cTimeout | ||||
| 			for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read clear address") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Generate stop condition | ||||
| 			i2c.Bus.CR1 |= stm32.I2C_CR1_STOP | ||||
| 
 | ||||
| 			timeout = i2cTimeout | ||||
| 			for (i2c.Bus.SR1 & stm32.I2C_SR1_RxNE) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read 1 byte") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Read and return data byte from I2C data register | ||||
| 			r[0] = byte(i2c.Bus.DR) | ||||
| 
 | ||||
| 			// wait for stop | ||||
| 			return i2c.waitForStop() | ||||
| 
 | ||||
| 		case 2: | ||||
| 			// enable pos | ||||
| 			i2c.Bus.CR1 |= stm32.I2C_CR1_POS | ||||
| 
 | ||||
| 			// Enable ACK of received data | ||||
| 			i2c.Bus.CR1 |= stm32.I2C_CR1_ACK | ||||
| 
 | ||||
| 			// send address | ||||
| 			err = i2c.sendAddress(uint8(addr), false) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// clear address here | ||||
| 			timeout := i2cTimeout | ||||
| 			for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read clear address") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Disable ACK of received data | ||||
| 			i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK | ||||
| 
 | ||||
| 			// wait for btf. we need a longer timeout here than normal. | ||||
| 			timeout = 1000 | ||||
| 			for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read 2 bytes") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Generate stop condition | ||||
| 			i2c.Bus.CR1 |= stm32.I2C_CR1_STOP | ||||
| 
 | ||||
| 			// read the 2 bytes by reading twice. | ||||
| 			r[0] = byte(i2c.Bus.DR) | ||||
| 			r[1] = byte(i2c.Bus.DR) | ||||
| 
 | ||||
| 			// wait for stop | ||||
| 			return i2c.waitForStop() | ||||
| 
 | ||||
| 		case 3: | ||||
| 			// Enable ACK of received data | ||||
| 			i2c.Bus.CR1 |= stm32.I2C_CR1_ACK | ||||
| 
 | ||||
| 			// send address | ||||
| 			err = i2c.sendAddress(uint8(addr), false) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// clear address here | ||||
| 			timeout := i2cTimeout | ||||
| 			for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read clear address") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Enable ACK of received data | ||||
| 			i2c.Bus.CR1 |= stm32.I2C_CR1_ACK | ||||
| 
 | ||||
| 			// wait for btf. we need a longer timeout here than normal. | ||||
| 			timeout = 1000 | ||||
| 			for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					println("I2C timeout on read 3 bytes") | ||||
| 					return errors.New("I2C timeout on read 3 bytes") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Disable ACK of received data | ||||
| 			i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK | ||||
| 
 | ||||
| 			// read the first byte | ||||
| 			r[0] = byte(i2c.Bus.DR) | ||||
| 
 | ||||
| 			timeout = 1000 | ||||
| 			for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read 3 bytes") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Generate stop condition | ||||
| 			i2c.Bus.CR1 |= stm32.I2C_CR1_STOP | ||||
| 
 | ||||
| 			// read the last 2 bytes by reading twice. | ||||
| 			r[1] = byte(i2c.Bus.DR) | ||||
| 			r[2] = byte(i2c.Bus.DR) | ||||
| 
 | ||||
| 			// wait for stop | ||||
| 			return i2c.waitForStop() | ||||
| 
 | ||||
| 		default: | ||||
| 			// more than 3 bytes of data to read | ||||
| 
 | ||||
| 			// send address | ||||
| 			err = i2c.sendAddress(uint8(addr), false) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			// clear address here | ||||
| 			timeout := i2cTimeout | ||||
| 			for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read clear address") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			for i := 0; i < len(r)-3; i++ { | ||||
| 				// Enable ACK of received data | ||||
| 				i2c.Bus.CR1 |= stm32.I2C_CR1_ACK | ||||
| 
 | ||||
| 				// wait for btf. we need a longer timeout here than normal. | ||||
| 				timeout = 1000 | ||||
| 				for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 { | ||||
| 					timeout-- | ||||
| 					if timeout == 0 { | ||||
| 						println("I2C timeout on read 3 bytes") | ||||
| 						return errors.New("I2C timeout on read 3 bytes") | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				// read the next byte | ||||
| 				r[i] = byte(i2c.Bus.DR) | ||||
| 			} | ||||
| 
 | ||||
| 			// wait for btf. we need a longer timeout here than normal. | ||||
| 			timeout = 1000 | ||||
| 			for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read more than 3 bytes") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Disable ACK of received data | ||||
| 			i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK | ||||
| 
 | ||||
| 			// get third from last byte | ||||
| 			r[len(r)-3] = byte(i2c.Bus.DR) | ||||
| 
 | ||||
| 			// Generate stop condition | ||||
| 			i2c.Bus.CR1 |= stm32.I2C_CR1_STOP | ||||
| 
 | ||||
| 			// get second from last byte | ||||
| 			r[len(r)-2] = byte(i2c.Bus.DR) | ||||
| 
 | ||||
| 			timeout = i2cTimeout | ||||
| 			for (i2c.Bus.SR1 & stm32.I2C_SR1_RxNE) == 0 { | ||||
| 				timeout-- | ||||
| 				if timeout == 0 { | ||||
| 					return errors.New("I2C timeout on read last byte of more than 3") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// get last byte | ||||
| 			r[len(r)-1] = byte(i2c.Bus.DR) | ||||
| 
 | ||||
| 			// wait for stop | ||||
| 			return i2c.waitForStop() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| const i2cTimeout = 500 | ||||
| 
 | ||||
| // signalStart sends a start signal. | ||||
| func (i2c I2C) signalStart() error { | ||||
| 	// Wait until I2C is not busy | ||||
| 	timeout := i2cTimeout | ||||
| 	for (i2c.Bus.SR2 & stm32.I2C_SR2_BUSY) > 0 { | ||||
| 		timeout-- | ||||
| 		if timeout == 0 { | ||||
| 			return errors.New("I2C busy on start") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// clear stop | ||||
| 	i2c.Bus.CR1 &^= stm32.I2C_CR1_STOP | ||||
| 
 | ||||
| 	// Generate start condition | ||||
| 	i2c.Bus.CR1 |= stm32.I2C_CR1_START | ||||
| 
 | ||||
| 	// Wait for I2C EV5 aka SB flag. | ||||
| 	timeout = i2cTimeout | ||||
| 	for (i2c.Bus.SR1 & stm32.I2C_SR1_SB) == 0 { | ||||
| 		timeout-- | ||||
| 		if timeout == 0 { | ||||
| 			return errors.New("I2C timeout on start") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // signalStop sends a stop signal and waits for it to succeed. | ||||
| func (i2c I2C) signalStop() error { | ||||
| 	// Generate stop condition | ||||
| 	i2c.Bus.CR1 |= stm32.I2C_CR1_STOP | ||||
| 
 | ||||
| 	// wait for stop | ||||
| 	return i2c.waitForStop() | ||||
| } | ||||
| 
 | ||||
| // waitForStop waits after a stop signal. | ||||
| func (i2c I2C) waitForStop() error { | ||||
| 	// Wait until I2C is stopped | ||||
| 	timeout := i2cTimeout | ||||
| 	for (i2c.Bus.SR1 & stm32.I2C_SR1_STOPF) > 0 { | ||||
| 		timeout-- | ||||
| 		if timeout == 0 { | ||||
| 			println("I2C timeout on wait for stop signal") | ||||
| 			return errors.New("I2C timeout on wait for stop signal") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Send address of device we want to talk to | ||||
| func (i2c I2C) sendAddress(address uint8, write bool) error { | ||||
| 	data := (address << 1) | ||||
| 	if !write { | ||||
| 		data |= 1 // set read flag | ||||
| 	} | ||||
| 
 | ||||
| 	i2c.Bus.DR = stm32.RegValue(data) | ||||
| 
 | ||||
| 	// Wait for I2C EV6 event. | ||||
| 	// Destination device acknowledges address | ||||
| 	timeout := i2cTimeout | ||||
| 	if write { | ||||
| 		// EV6 which is ADDR flag. | ||||
| 		for i2c.Bus.SR1&stm32.I2C_SR1_ADDR == 0 { | ||||
| 			timeout-- | ||||
| 			if timeout == 0 { | ||||
| 				return errors.New("I2C timeout on send write address") | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		timeout = i2cTimeout | ||||
| 		for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY|stm32.I2C_SR2_TRA) == 0 { | ||||
| 			timeout-- | ||||
| 			if timeout == 0 { | ||||
| 				return errors.New("I2C timeout on send write address") | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		// I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED which is ADDR flag. | ||||
| 		for (i2c.Bus.SR1 & stm32.I2C_SR1_ADDR) == 0 { | ||||
| 			timeout-- | ||||
| 			if timeout == 0 { | ||||
| 				return errors.New("I2C timeout on send read address") | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // WriteByte writes a single byte to the I2C bus. | ||||
| func (i2c I2C) WriteByte(data byte) error { | ||||
| 	// Send data byte | ||||
| 	i2c.Bus.DR = stm32.RegValue(data) | ||||
| 
 | ||||
| 	// Wait for I2C EV8_2 when data has been physically shifted out and | ||||
| 	// output on the bus. | ||||
| 	// I2C_EVENT_MASTER_BYTE_TRANSMITTED is TXE flag. | ||||
| 	timeout := i2cTimeout | ||||
| 	for i2c.Bus.SR1&stm32.I2C_SR1_TxE == 0 { | ||||
| 		timeout-- | ||||
| 		if timeout == 0 { | ||||
| 			return errors.New("I2C timeout on write") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -21,15 +21,21 @@ func putchar(c byte) { | |||
| 
 | ||||
| // initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz). | ||||
| func initCLK() { | ||||
| 	stm32.FLASH.ACR |= stm32.FLASH_ACR_LATENCY_2 // Two wait states, per datasheet | ||||
| 	stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE1_DIV_2 // prescale PCLK1 = HCLK/2 | ||||
| 	stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE2_DIV_4 // prescale PCLK2 = HCLK/4 | ||||
| 	stm32.RCC.CR |= stm32.RCC_CR_HSEON           // enable HSE clock | ||||
| 	stm32.FLASH.ACR |= stm32.FLASH_ACR_LATENCY_2    // Two wait states, per datasheet | ||||
| 	stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE1_DIV_2    // prescale PCLK1 = HCLK/2 | ||||
| 	stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE2_DIV_NONE // prescale PCLK2 = HCLK/1 | ||||
| 	stm32.RCC.CR |= stm32.RCC_CR_HSEON              // enable HSE clock | ||||
| 
 | ||||
| 	// wait for the HSEREADY flag | ||||
| 	for (stm32.RCC.CR & stm32.RCC_CR_HSERDY) == 0 { | ||||
| 	} | ||||
| 
 | ||||
| 	stm32.RCC.CR |= stm32.RCC_CR_HSION // enable HSI clock | ||||
| 
 | ||||
| 	// wait for the HSIREADY flag | ||||
| 	for (stm32.RCC.CR & stm32.RCC_CR_HSIRDY) == 0 { | ||||
| 	} | ||||
| 
 | ||||
| 	stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLSRC   // set PLL source to HSE | ||||
| 	stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLMUL_9 // multiply by 9 | ||||
| 	stm32.RCC.CR |= stm32.RCC_CR_PLLON        // enable the PLL | ||||
|  |  | |||
|  | @ -12,5 +12,7 @@ | |||
| 	"extra-files": [ | ||||
| 		"src/device/stm32/stm32f103xx.s" | ||||
| 	], | ||||
| 	"flash": "openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c 'program {hex} reset exit'" | ||||
| 	"flash": "openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c 'program {hex} reset exit'", | ||||
| 	"ocd-daemon": ["openocd", "-f", "interface/stlink-v2.cfg", "-f", "target/stm32f1x.cfg"], | ||||
| 	"gdb-initial-cmds": ["target remote :3333", "monitor halt", "load", "monitor reset", "c"] | ||||
| } | ||||
|  |  | |||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 Ron Evans
						Ron Evans